/* ============================================================================
   ClockWitness — sistema de design "Turno"
   ============================================================================

   Uma folha de estilo, partilhada pelo site público e pela aplicacao. Se um
   ecra precisar de CSS proprio, isso e sinal de que falta aqui um componente --
   nao de que o ecra e especial. Ver
   docs/superpowers/specs/2026-08-05-site-publico-e-backoffice-design.md §4.

   TESE
   Monitorizacao de equipas remotas com cara humana. Tatil e quente, o oposto de
   uma sala de controlo. A metafora e o cartao de ponto: um objecto fisico, de
   papel grosso, carimbado.

   AS DUAS REGRAS QUE NAO SE QUEBRAM

   1. Ha UMA cor de marca (--accent, azeitona). A argila (--clay) e so para
      exececoes -- intervalo descartado, aviso que exige accao. Nunca e botao,
      nunca e segunda cor de marca, e nunca significa que uma pessoa se portou
      mal. O erro que define esta categoria inteira (Monitask, Hubstaff, Time
      Doctor) e o semaforo de produtividade vermelho/amarelo/verde por captura
      de ecra. Aqui nao existe em forma nenhuma.

   2. O nivel de actividade usa uma rampa de UMA SO MATIZ. Le-se intensidade,
      nunca julgamento.

   NOMES DE CLASSE
   Compostos e especificos: `turno-card`, `metric-card`, `data-table`. Nunca
   palavras genericas soltas como `.app`, `.card` ou `.meta` -- durante a
   prototipagem a classe `app` foi usada ao mesmo tempo para a moldura da
   aplicacao (com min-height) e para o nome de uma aplicacao dentro de um cartao
   de captura, e a segunda herdou a altura da primeira. Os cartoes ficaram com
   800px de altura vazia e a causa demorou a encontrar porque parecia um
   problema de espacamento.

   FONTES
   Auto-alojadas em static/fonts/, nunca carregadas do Google. O argumento
   comercial principal deste produto e que os dados ficam no servidor do
   cliente; carregar tipos de letra de fonts.gstatic.com envia o IP de cada
   visitante para a Google antes de haver consentimento nenhum, na propria
   pagina que existe para vender privacidade. Ver §3 D1 do desenho.
   ========================================================================== */


/* ============================================================================
   TIPOS DE LETRA
   ========================================================================== */

/* Os ficheiros ficam em static/fonts/, uma pasta por familia -- nao soltos
   directamente em static/fonts/ -- porque cada familia traz a sua propria
   licenca ao lado (OFL.txt para as duas primeiras, LICENSE.txt com o texto
   da ITF Free Font License para a Switzer) e as tres nao partilham a mesma
   licenca (§3 D1 do desenho). Ver NOTICE.md na raiz do repositorio para
   origem e versao de cada activo. As pilhas de recurso sao deliberadas: se
   um WOFF2 faltar, a pagina continua legivel em vez de cair para Times. */

@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../fonts/bricolage-grotesque/BricolageGrotesque-Variable.477b564b86e0.woff2") format("woff2-variations");
  font-weight: 200 800;
  font-display: swap;
  font-style: normal;
}

@font-face {
  font-family: "Switzer";
  src: url("../fonts/switzer/Switzer-Variable.4523d2c62663.woff2") format("woff2-variations");
  font-weight: 300 700;
  font-display: swap;
  font-style: normal;
}

@font-face {
  font-family: "DM Mono";
  src: url("../fonts/dm-mono/DMMono-Regular.e1ed461ac183.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
  font-style: normal;
}

@font-face {
  font-family: "DM Mono";
  src: url("../fonts/dm-mono/DMMono-Medium.c4598219c4b8.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
  font-style: normal;
}


/* ============================================================================
   TOKENS
   ========================================================================== */

:root {
  /* Cor */
  --bg:          #EDE7DF;
  --surface:     #FBF7F1;
  --ink:         #241D17;
  --ink-2:       #6B5D50;
  --rule:        #D8CFC3;

  --accent:      #4A5D3A;
  --accent-2:    #38442C;
  --accent-pale: #D9E0CB;

  --clay:        #B8654A;
  --clay-pale:   #F1DAD1;

  /* Rampa de actividade -- uma so matiz, do claro ao escuro. Cinco degraus
     porque abaixo disso os intervalos deixam de se distinguir e acima disso
     ninguem le a diferenca. */
  --act-1: #DDE4CE;
  --act-2: #B9C9A0;
  --act-3: #8CA06A;
  --act-4: #63794A;
  --act-5: #3A4A2C;

  /* Raio */
  --r-s: 8px;
  --r-m: 14px;
  --r-l: 22px;

  /* Sombra */
  --shadow-card: 0 1px 2px rgba(36, 29, 23, .05), 0 12px 28px -8px rgba(36, 29, 23, .16);
  --shadow-soft: 0 1px 1px rgba(36, 29, 23, .04), 0 6px 16px -6px rgba(36, 29, 23, .10);

  /* Tipos de letra */
  --f-display: "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
  --f-body:    "Switzer", ui-sans-serif, system-ui, sans-serif;
  --f-mono:    "DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Medidas */
  --shell: 1280px;
}


/* ============================================================================
   BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
button { font: inherit; }
a { color: inherit; }
h1, h2, h3, h4, p, figure { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

::selection { background: var(--accent); color: var(--surface); }

/* O foco de teclado e sempre visivel. Nao ha excepcoes e nao se remove com
   outline:none em lado nenhum. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2.5px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Grao de papel. E um SVG embutido, nao uma imagem -- nenhum pedido de rede,
   nenhum ficheiro para servir, e continua a funcionar offline. mix-blend-mode
   com opacidade baixa para nao interferir com o contraste do texto. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  opacity: .05;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}


/* ============================================================================
   LAYOUT
   ========================================================================== */

.shell {
  max-width: var(--shell);
  margin: 0 auto;
  padding-inline: clamp(20px, 5vw, 64px);
}

.section-label {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin: 0 0 22px;
  font-family: var(--f-mono);
  font-size: .78rem;
  /* `.section-label` também é usada em <h2>/<h3> reais (ver o dia de
     trabalho): sem isto herdavam o negrito por omissão do agente de
     utilizador para cabeçalhos, que nenhum <p> desta classe alguma vez
     teve. Explícito para os dois casos ficarem com o mesmo peso. */
  font-weight: 400;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.section-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}

.eyebrow {
  display: block;
  margin-bottom: 14px;
  font-family: var(--f-mono);
  font-size: .8rem;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent);
}


/* ============================================================================
   TIPOGRAFIA
   ========================================================================== */

.title-xl,
.title-l,
.title-m,
.title-s {
  font-family: var(--f-display);
  font-weight: 700;
  letter-spacing: -.015em;
  line-height: 1.04;
}

.title-xl { font-size: clamp(2.4rem, 6vw, 4.6rem); line-height: .96; }
.title-l  { font-size: clamp(2.1rem, 4.4vw, 3.4rem); }
.title-m  { font-size: clamp(1.4rem, 2.4vw, 1.9rem); line-height: 1.12; }
.title-s  { font-size: 1.05rem; line-height: 1.2; }

.lede {
  max-width: 46ch;
  font-size: clamp(1rem, 1.6vw, 1.12rem);
  color: var(--ink-2);
}

/* Numeros, horas, totais e identificadores. tabular-nums e obrigatorio: sem
   ele uma coluna de durações dança da esquerda para a direita a cada linha. */
.num {
  font-family: var(--f-mono);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}


/* ============================================================================
   BOTÕES
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 11px 22px;
  border: 1.5px solid transparent;
  border-radius: 10px;
  font-family: var(--f-body);
  font-size: .92rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: transform .15s ease, background .15s ease, color .15s ease;
}
.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--accent); color: var(--surface); box-shadow: 0 1px 0 rgba(0, 0, 0, .05); }
.btn-primary:hover { background: var(--accent-2); }

.btn-ghost { background: transparent; border-color: var(--ink); color: var(--ink); }
.btn-ghost:hover { background: var(--ink); color: var(--surface); }

.btn-quiet { background: transparent; border-color: var(--rule); color: var(--ink-2); }
.btn-quiet:hover { border-color: var(--ink-2); color: var(--ink); }

.btn-small { padding: 8px 16px; font-size: .82rem; }


/* ============================================================================
   CARTÃO DE TURNO — a assinatura
   ============================================================================
   O dia de uma pessoa como cartao de ponto fisico. O mesmo componente no site
   publico, na lista da equipa e no detalhe de sessao: uma ideia so, em todo o
   lado.

   Alimenta-se de campos que ja existem -- Interval.activity_percent,
   Interval.idle_resolution, Pause e Screenshot. Nenhum campo novo e preciso.

   --hole tem de ser a cor do que esta POR TRAS do cartao, porque as
   perfuracoes sao buracos: se o cartao estiver sobre --surface em vez de --bg,
   quem o usa redefine --hole no elemento.
   ========================================================================== */

.turno-card {
  --hole: var(--bg);
  position: relative;
  padding: 22px 22px 20px 38px;
  background: var(--surface);
  border-radius: var(--r-l);
  box-shadow: var(--shadow-card);
}

/* As perfuracoes. Um radial-gradient repetido em Y, nao imagens. */
.turno-card::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 26px;
  background-image: radial-gradient(circle at center, var(--hole) 4.5px, transparent 5px);
  background-size: 26px 24px;
  background-repeat: repeat-y;
  background-position: center top;
}

/* A linha de corte, a seguir as perfuracoes. */
.turno-card::after {
  content: "";
  position: absolute;
  left: 26px;
  top: 14px;
  bottom: 14px;
  width: 1px;
  background: repeating-linear-gradient(var(--rule) 0 4px, transparent 4px 9px);
}

.turno-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
}
.turno-name { font-family: var(--f-display); font-weight: 700; font-size: 1.18rem; }
.turno-project { margin-top: 2px; font-size: .86rem; color: var(--ink-2); }

.turno-status {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px 5px 8px;
  border-radius: 999px;
  font-family: var(--f-mono);
  font-size: .7rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.turno-status .dot { width: 6px; height: 6px; border-radius: 50%; }

.turno-status.is-live { color: var(--accent-2); background: var(--accent-pale); }
.turno-status.is-live .dot { background: var(--accent); animation: cw-pulse 1.8s ease-in-out infinite; }

.turno-status.is-done { color: var(--ink-2); background: var(--rule); }
.turno-status.is-done .dot { background: var(--ink-2); }

@keyframes cw-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

.turno-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.turno-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.turno-total { font-family: var(--f-mono); font-weight: 500; font-size: 1.5rem; font-variant-numeric: tabular-nums; }
.turno-total-label { font-size: .74rem; color: var(--ink-2); }
.turno-activity { text-align: right; }
.turno-activity b { font-family: var(--f-mono); font-size: 1.05rem; font-variant-numeric: tabular-nums; font-weight: 500; }
.turno-activity span { display: block; font-size: .68rem; color: var(--ink-2); }


/* ---- Carimbos --------------------------------------------------------------
   Contorno solido = facto assente (a hora de entrada ja aconteceu).
   Tracejado = ainda em aberto (a sessao nao terminou). A distincao e
   deliberada: um carimbo tracejado le-se como "por confirmar" sem precisar de
   legenda nenhuma.
   -------------------------------------------------------------------------- */

.stamps { display: flex; gap: 14px; margin-bottom: 16px; }

.stamp {
  position: relative;
  padding: 7px 14px 6px;
  border: 2px solid var(--accent);
  border-radius: 9px 7px 10px 6px;
  transform: rotate(-2.5deg);
  box-shadow: 0 0 0 3px rgba(74, 93, 58, .12);
}
.stamp:nth-child(2) { transform: rotate(2deg); }

.stamp-label {
  display: block;
  margin-bottom: 1px;
  font-family: var(--f-body);
  font-size: .6rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--accent);
  opacity: .8;
}
.stamp-time {
  font-family: var(--f-mono);
  font-weight: 500;
  font-size: 1.05rem;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.stamp.is-pending { border-style: dashed; border-color: var(--ink-2); box-shadow: none; transform: rotate(1.5deg); }
.stamp.is-pending .stamp-label,
.stamp.is-pending .stamp-time { color: var(--ink-2); }


/* ---- Banda de temperatura --------------------------------------------------
   O nivel de actividade ao longo do dia. Cada `span` e um intervalo. A cor sai
   da rampa de uma so matiz (--act-1..5); nunca de um semaforo.
   -------------------------------------------------------------------------- */

.temp-band-wrap { margin-bottom: 16px; }

.temp-caption {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 6px;
  font-size: .72rem;
  color: var(--ink-2);
}
.temp-caption .val { font-family: var(--f-mono); font-weight: 500; color: var(--ink); }

.temp-band {
  display: flex;
  gap: 1.5px;
  height: 11px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--rule);
}
.temp-band span { flex: 1; }

.temp-band .act-1 { background: var(--act-1); }
.temp-band .act-2 { background: var(--act-2); }
.temp-band .act-3 { background: var(--act-3); }
.temp-band .act-4 { background: var(--act-4); }
.temp-band .act-5 { background: var(--act-5); }

/* Pausa: o papel a mostrar-se atraves da banda. Ausencia, nao falha. */
.temp-band .is-pause { background: var(--rule); }

/* Intervalo descartado por inactividade: e a unica excepcao que justifica
   argila, e mesmo assim tratada como textura e nao como alarme. */
.temp-band .is-discard {
  background-color: var(--clay-pale);
  background-image: repeating-linear-gradient(-45deg, var(--clay) 0 2px, transparent 2px 5px);
}

/* Intervalo sem prova nenhuma: mesmo problema que .daybar-block.is-without-
   evidence tinha (ver o comentario la, mais abaixo neste ficheiro) -- um
   preenchimento liso a --clay-pale, convertido a cinzento, mede quase o
   mesmo que .act-1 (222 contra 225 em 255): os dois estados que este produto
   existe para separar (um conta para o total, o outro fica fora dele, D9)
   ficavam identicos sem cor.

   Em vez de preenchimento, uma moldura vazia -- sem fundo nenhum, so o
   contorno a --clay -- que deixa ver o --rule da banda por dentro, tal como
   .is-pause ja mostra. A diferenca entre os dois deixa de ser so a cor: pausa
   nao tem contorno nenhum (ausencia lisa), sem prova tem-no (ausencia que
   pesa contra o total). Essa distincao de FORMA sobrevive a qualquer
   conversao de cor. */
.temp-band .is-without-evidence {
  background-color: transparent;
  box-shadow: inset 0 0 0 1.5px var(--clay);
}


/* ============================================================================
   CARTÃO DE MÉTRICA
   ========================================================================== */

.metric-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
  overflow: hidden;
}

.metric-card { padding: 16px 18px 18px; background: var(--surface); }
.metric-card .eyebrow { margin-bottom: 10px; font-size: .7rem; }
.metric-value {
  display: block;
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 2rem;
  line-height: 1;
  letter-spacing: -.02em;
}
.metric-value em { font-style: normal; font-size: .95rem; color: var(--ink-2); margin-left: 3px; }
.metric-note { display: block; margin-top: 7px; font-size: .76rem; color: var(--ink-2); }

/* A unica metrica que pode gritar e a que exige accao de quem esta a ler.
   Um filete de argila no topo, nao o cartao inteiro pintado. */
.metric-card.needs-action { border-top: 3px solid var(--clay); }
/* --clay mede 3,94:1 sobre --surface. A .7rem (11,2px) é texto pequeno e
   falha AA. --clay-ink mede 6,37:1. Ver D10 e a secção de tokens da Fase —
   O dia de trabalho, mais abaixo neste ficheiro. */
.metric-card.needs-action .eyebrow { color: var(--clay-ink); }


/* ============================================================================
   ETIQUETAS DE ESTADO
   ========================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-family: var(--f-mono);
  font-size: .68rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
}
.badge.is-active  { border-color: var(--accent); color: var(--accent); background: var(--accent-pale); }
.badge.is-pending { border-style: dashed; }
/* --clay sobre --clay-pale mede 3,14:1. O bordo pode ficar em --clay
   (limiar de 3:1 para traço); o TEXTO passa a --clay-ink, 5,08:1. */
.badge.is-problem { border-color: var(--clay); color: var(--clay-ink); background: var(--clay-pale); }

/* A cor de uma Activity (apps.tracking.models), na coluna "Cor" de
   dashboard/activity_list.html -- um quadrado sólido, a cor real vem inline
   (style="background-color: ...") porque é dado do registo, não algo que o
   CSS possa saber de antemão. Bordo sempre visível: uma cor clara sobre o
   fundo claro do cartão ficaria sem contorno nenhum sem ele. */
.color-swatch {
  display: inline-block;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  border: 1px solid var(--rule);
  vertical-align: middle;
}


/* ============================================================================
   TABELA DE DADOS
   ========================================================================== */

.data-table { width: 100%; border-collapse: collapse; }

.data-table th {
  padding: 0 14px 10px 0;
  border-bottom: 1px solid var(--rule);
  font-family: var(--f-mono);
  font-size: .7rem;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  text-align: left;
  color: var(--ink-2);
}
.data-table td {
  padding: 13px 14px 13px 0;
  border-bottom: 1px solid var(--rule);
  font-size: .92rem;
  vertical-align: middle;
}
.data-table tr:last-child td { border-bottom: 0; }
.data-table td.num-cell { font-family: var(--f-mono); font-variant-numeric: tabular-nums; text-align: right; }

/* Tabelas largas nunca fazem a pagina rolar na horizontal: rolam dentro da
   sua propria caixa. */
.table-scroll { overflow-x: auto; }

/* Uma .data-table cujas celulas sao os proprios campos de um formulario --
   Entradas de tempo em massa (F10) e o primeiro caso. Os campos nao vivem
   dentro de .field (esse wrapper e feito para uma coluna, nao para uma
   grelha de N linhas), por isso reaproveita-se aqui a mesma borda/raio/tipo
   de letra de .field input, so escopados a esta tabela em vez de a .field. */
.data-table.is-editable select,
.data-table.is-editable input[type="datetime-local"],
.data-table.is-editable input[type="text"] {
  width: 100%;
  padding: 8px 10px;
  border: 1.5px solid var(--rule);
  border-radius: var(--r-s);
  background: var(--bg);
  font-family: var(--f-body);
  font-size: .88rem;
  color: var(--ink);
}
.data-table.is-editable tr.has-error select,
.data-table.is-editable tr.has-error input { border-color: var(--clay); }
.data-table.is-editable .row-errors { margin: 4px 0 0; font-size: .8rem; color: var(--clay-ink); }


/* ============================================================================
   ESTADO VAZIO
   ============================================================================
   Um ecra vazio e um convite a agir, nao um aviso de que algo falhou. Por isso
   tem sempre um titulo que diz o que se pode fazer, e nunca a palavra "erro".
   ========================================================================== */

.empty-state {
  padding: 44px 32px;
  border: 1px dashed var(--rule);
  border-radius: var(--r-m);
  text-align: center;
  background: var(--surface);
}
.empty-state .title-s { margin-bottom: 8px; }
.empty-state p { max-width: 46ch; margin: 0 auto 18px; font-size: .9rem; color: var(--ink-2); }
/* `.empty-state h2.title-s` -- acrescentado na revisão adversarial da
   Tarefa A (sessão 018), quando dashboard/dia.html trocou o título do
   estado vazio de <p class="title-s"> para <h2 class="title-s">.

   `.empty-state p` (0,1,1) tinha especificidade maior do que `.title-s`
   (0,1,0) e, por isso, era ela -- não `.title-s` -- quem de facto definia
   font-size/color/max-width do título enquanto ele foi <p>: apanhava-o pelo
   TIPO de elemento, não pela classe. Passar a <h2> tira-o dessa regra
   inteira (deixa de haver `<p>`), e sem esta reposição o título ficava
   maior, mais escuro (herdava --ink em vez de --ink-2) e sem largura
   máxima nem centragem.

   `margin-bottom` NÃO precisa de repetição: `.empty-state .title-s` (duas
   classes, 0,2,0) já ganhava a `.empty-state p` (0,1,1) nessa propriedade
   antes desta mudança, e continua a aplicar-se por classe, tag nenhuma.

   Propositadamente scoped a `h2.title-s`, e NÃO uma alteração a
   `.empty-state p`: há treze outros sítios com `<p class="title-s">` dentro
   de `.empty-state` (session_list, project_list, project_members,
   dia_escolher, session_detail, _shift_grid, folha, team, report×5) que
   continuam a depender dessa regra tal como está -- mexer nela obrigava a
   verificar esses treze ecrãs, que esta tarefa não toca. */
.empty-state h2.title-s { max-width: 46ch; margin-inline: auto; font-size: .9rem; color: var(--ink-2); }


/* ============================================================================
   AVISO PERSISTENTE
   ========================================================================== */

.notice {
  padding: 14px 18px;
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--r-s) var(--r-s) 0;
  background: var(--accent-pale);
  font-size: .92rem;
}
.notice.needs-action { border-left-color: var(--clay); background: var(--clay-pale); }


/* ============================================================================
   FORMULÁRIO EM CARTÃO
   ========================================================================== */

.form-card {
  padding: 26px 28px 28px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
  box-shadow: var(--shadow-soft);
}
.field { margin-bottom: 18px; }
.field > label {
  display: block;
  margin-bottom: 6px;
  font-size: .82rem;
  font-weight: 600;
  color: var(--ink);
}
.field input[type="text"],
.field input[type="email"],
.field input[type="password"],
.field input[type="number"],
.field input[type="date"],
.field select,
.field textarea {
  width: 100%;
  padding: 10px 13px;
  border: 1.5px solid var(--rule);
  border-radius: var(--r-s);
  background: var(--bg);
  font-family: var(--f-body);
  font-size: .95rem;
  color: var(--ink);
}
.field .help { margin-top: 6px; font-size: .78rem; color: var(--ink-2); }
/* 3,94:1 a 13,1px falha AA. --clay-ink: 6,37:1. */
.field .error { margin-top: 6px; font-size: .82rem; color: var(--clay-ink); }
.field.has-error input,
.field.has-error select,
.field.has-error textarea { border-color: var(--clay); }


/* ============================================================================
   NAVEGAÇÃO DA APLICAÇÃO
   ============================================================================
   O estado activo e obrigatorio. A navegacao anterior nao o tinha, e usava a
   mesma classe CSS dos timestamps -- estava literalmente estilizada como
   metadado.
   ========================================================================== */

.app-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 14px clamp(16px, 3vw, 32px);
  background: var(--ink);
  color: var(--bg);
}
.app-nav a { text-decoration: none; }

.app-nav-group { display: flex; align-items: center; gap: 4px; }

.app-nav-link {
  padding: 8px 14px;
  border-radius: var(--r-s);
  font-size: .92rem;
  color: rgba(237, 231, 223, .72);
  transition: background .15s ease, color .15s ease;
}
.app-nav-link:hover { color: var(--bg); background: rgba(237, 231, 223, .08); }
.app-nav-link[aria-current="page"] { color: var(--ink); background: var(--accent-pale); font-weight: 600; }


/* ============================================================================
   MARCA
   ========================================================================== */

.wordmark {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 1.15rem;
  text-decoration: none;
  white-space: nowrap;
}
/* A perfuracao do cartao de ponto, reduzida a um simbolo. */
.wordmark .hole {
  flex: none;
  width: 15px;
  height: 15px;
  border: 2.5px solid var(--accent);
  border-radius: 50%;
}


/* ============================================================================
   RESPOSTA A ECRÃS PEQUENOS
   ============================================================================
   Verificado ate 400px. Abaixo disso nao ha telemovel a serio.
   ========================================================================== */

@media (max-width: 980px) {
  .metric-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}

@media (max-width: 680px) {
  .app-nav { flex-wrap: wrap; }
  .app-nav-group { flex-wrap: wrap; }
  .stamps { flex-wrap: wrap; gap: 10px; }
  .turno-card { padding: 18px 18px 16px 34px; }
}

@media (max-width: 400px) {
  body { font-size: 15px; }
  .turno-head { flex-direction: column; }
  .metric-grid { grid-template-columns: 1fr; }
}


/* ============================================================================
   FASE 3 — NAVEGAÇÃO AGRUPADA E O ECRÃ HOJE
   ============================================================================
   Secção acrescentada pela Fase 3 (docs/superpowers/specs/
   2026-08-05-site-publico-e-backoffice-design.md §7, §8). Só acrescenta --
   nenhuma regra acima desta linha foi alterada. Componentes novos, não
   variantes dos existentes: `.app-nav-groups`/`.app-nav-account` cobrem o que
   `.app-nav-group` sozinho não cobria (vários grupos e o bloco de conta
   lado a lado), e `.shift-grid`/`.today-*` são o layout de Hoje à volta de
   `.metric-grid`, `.notice` e `.turno-card`, todos já existentes e usados
   sem alteração nenhuma.
   ========================================================================== */

.app-nav-groups {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
}

/* Focus visibility, scoped to this dark bar only -- not a change to the
   global a:focus-visible/button:focus-visible rule above (which stays
   --accent everywhere else it applies). --accent against --ink measures
   under 3:1, the WCAG threshold for a non-text UI indicator: an olive-green
   ring is close to invisible on the nav's own near-black background. --bg
   (the page's own cream) clears that easily and appears nowhere else this
   focus ring could be confused for anything but a focus ring. */
.app-nav a:focus-visible,
.app-nav button:focus-visible {
  outline-color: var(--bg);
}

/* Filete a separar os grupos, não outra cor -- a mesma ideia de --rule, só
   que sobre o fundo escuro da barra em vez do --surface claro. */
.app-nav-groups .app-nav-group + .app-nav-group {
  padding-left: 22px;
  border-left: 1px solid rgba(237, 231, 223, .16);
}

.app-nav-account {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: .82rem;
  color: rgba(237, 231, 223, .72);
  white-space: nowrap;
}

.app-nav-logout {
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
  font-size: inherit;
}
.app-nav-logout:hover { color: var(--bg); }

/* A minha conta -- o email em .app-nav-account passou a link (apps.accounts.
   views.account_settings). Sem isto herdava só a regra genérica ".app-nav a
   { text-decoration: none; }" (mais acima) e ficava indistinguível de texto
   morto -- nada de cor, sublinhado ou :hover próprios, ao lado de
   .app-nav-logout, que sempre teve os três. Mesmo tratamento que essa
   vizinha: sublinhado sempre visível (é a única pista de que aquilo se
   clica), --bg no :hover e no próprio ecrã (aria-current). O :focus-visible
   já vem da regra ".app-nav a:focus-visible" acima. */
.app-nav-account a { color: inherit; text-decoration: underline; }
.app-nav-account a:hover { color: var(--bg); }
.app-nav-account a[aria-current="page"] { color: var(--bg); font-weight: 600; }

.today-metrics { margin-top: 22px; margin-bottom: 28px; }
.today-alerts { display: flex; flex-direction: column; gap: 12px; margin-bottom: 28px; }
.today-team { margin-top: 8px; }

.shift-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}

.turno-empty { margin-top: 2px; font-size: .88rem; color: var(--ink-2); }

@media (max-width: 680px) {
  .app-nav-account { width: 100%; justify-content: space-between; }
}

@media (max-width: 400px) {
  .shift-grid { grid-template-columns: 1fr; }
}


/* ============================================================================
   SITE PÚBLICO — FASE 2 (apps.site)
   ============================================================================
   Everything from here to the end of the file belongs to apps.site's five
   public pages (Início, Funcionalidades, Preços, Segurança e privacidade,
   Descarregar) plus their shared header/footer. Additive only: nothing
   above this banner is edited, no existing token is redefined. Every new
   component name is prefixed "site-" so it can never collide with a
   generic name some other screen already claims -- the same reason this
   file's own intro warns against bare names like .app or .card.
   ========================================================================== */

/* ---- Cabeçalho -------------------------------------------------------------
   Reuses .shell for the same max-width/gutter as every other section instead
   of defining its own, so the header, the content, and the footer align on
   one vertical edge at every viewport width.
   -------------------------------------------------------------------------- */

.site-header {
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}
.site-header-row {
  display: flex;
  align-items: center;
  gap: 24px;
  padding-block: 16px;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-inline: auto;
}
.site-nav-link {
  padding: 8px 12px;
  border-radius: var(--r-s);
  font-size: .92rem;
  text-decoration: none;
  color: var(--ink-2);
  transition: background .15s ease, color .15s ease;
}
.site-nav-link:hover { color: var(--ink); background: var(--bg); }
/* Same "state that survives being read out loud" as .app-nav-link's own
   [aria-current="page"] rule -- a colour change alone is not a state for
   anyone using a screen reader. */
.site-nav-link[aria-current="page"] { color: var(--ink); background: var(--accent-pale); font-weight: 600; }

.site-header-actions {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: none;
}

/* ---- Selector de língua -----------------------------------------------------
   One <form method="post"> per language, not a single <select>: a <select>
   would need JavaScript to submit on change (this project has none loaded on
   the public site, and D1b's "zero external resources" rule is not a reason
   to add a first inline script where a plain form already does the job).
   Two languages today read as a compact toggle; a third (D7 names Spanish)
   just adds a third button, because the markup already loops
   settings.LANGUAGES via {% get_available_languages %} in
   templates/site/base_public.html -- nothing here hardcodes "pt" or "en".
   -------------------------------------------------------------------------- */

.lang-switch {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: var(--bg);
}
.lang-switch form { display: contents; }
.lang-switch-option {
  padding: 5px 11px;
  border: none;
  border-radius: 999px;
  background: transparent;
  font-family: var(--f-mono);
  font-size: .74rem;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--ink-2);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.lang-switch-option:hover { color: var(--ink); }
.lang-switch-option.is-current { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-soft); }

/* ---- Herói -------------------------------------------------------------- */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 420px);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
  padding-block: clamp(48px, 8vw, 96px);
}
.hero-note { margin-top: 18px; font-size: .84rem; color: var(--ink-2); }
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
/* The hero's shift card is the same .turno-card component used everywhere
   else (§4.3 of the design) -- only a max-width so it does not stretch to
   the full width of its grid column on a wide screen. */
.hero-card { max-width: 400px; }

/* ---- Secções de conteúdo ------------------------------------------------- */

.site-section { padding-block: clamp(40px, 6vw, 80px); border-top: 1px solid var(--rule); }
.site-section:first-child { border-top: none; }
.site-section-head { max-width: 62ch; margin-bottom: clamp(28px, 4vw, 44px); }
.site-section-head .title-l { margin-top: 10px; }

/* ---- Passos ("Como funciona") -------------------------------------------- */

.step-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 28px;
}
.step { position: relative; padding-left: 46px; }
.step-num {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--surface);
  font-family: var(--f-mono);
  font-weight: 500;
  font-size: .92rem;
}
.step h3 { margin-bottom: 6px; }
.step p { color: var(--ink-2); font-size: .92rem; }

/* ---- Vantagens / pontos --------------------------------------------------
   Deliberately its own grid, not .metric-grid: a metric card's value is a
   number a person reads at a glance ("2 h 14 m"), and reusing it for a
   sentence-length description made every card read like a stray statistic.
   -------------------------------------------------------------------------- */

.point-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
  overflow: hidden;
}
.point-card { padding: 20px 22px 22px; background: var(--surface); }
.point-card h3 { margin-bottom: 8px; font-size: 1.02rem; }
.point-card p { font-size: .88rem; color: var(--ink-2); }

/* ---- Famílias de funcionalidades (página Funcionalidades) ---------------- */

.feature-group + .feature-group { margin-top: clamp(32px, 5vw, 56px); }
.feature-group-title { margin-bottom: 18px; }
.feature-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 22px 32px;
}
.feature-list dt { font-weight: 600; margin-bottom: 4px; }
.feature-list dd { margin: 0; font-size: .9rem; color: var(--ink-2); }

/* ---- Preços --------------------------------------------------------------- */

.plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 20px;
  align-items: stretch;
}
.plan-card {
  display: flex;
  flex-direction: column;
  padding: 26px 26px 28px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-l);
  box-shadow: var(--shadow-soft);
}
/* The middle "Negócio" plan is the one meant to be picked, the same way a
   pricing table has always signalled a recommendation -- via emphasis, not
   by putting it in --clay, which this file's own rules reserve for
   exceptions and never for marketing emphasis. */
.plan-card.is-recommended { border-color: var(--accent); box-shadow: var(--shadow-card); }
.plan-name { margin-bottom: 6px; }
.plan-audience { font-size: .88rem; color: var(--ink-2); margin-bottom: 18px; }
.plan-features { display: flex; flex-direction: column; gap: 10px; margin-bottom: 24px; flex: 1; }
.plan-features li { font-size: .88rem; padding-left: 20px; position: relative; }
/* A plain rule, not a checkmark glyph pretending to be an icon -- this
   file's own rule is "no emoji as icon", and a tick character carries the
   same "decoration doing a label's job" problem an emoji would. */
.plan-features li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .55em;
  width: 9px;
  height: 2px;
  background: var(--accent);
}

/* ---- Rodapé ---------------------------------------------------------------- */

.site-footer { border-top: 1px solid var(--rule); background: var(--surface); }
.site-footer-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr));
  gap: 28px;
  padding-block: 40px;
}
.site-footer-brand p { margin-top: 12px; font-size: .84rem; color: var(--ink-2); max-width: 34ch; }
.site-footer-links { display: flex; flex-direction: column; gap: 10px; }
.site-footer-links a { font-size: .88rem; text-decoration: none; color: var(--ink-2); }
.site-footer-links a:hover { color: var(--ink); }

/* ---- Aviso do instalador (página Descarregar) -----------------------------
   .notice already exists (transversal component); this just gives the
   ordered "what happens after install" steps a numbered layout consistent
   with .step-list above, reused rather than invented twice. */

/* list-style/padding zerados aqui e não no reset: o reset trata `ul`, e esta
   é uma `ol` de propósito (a ordem dos passos é significado, não decoração,
   e um leitor de ecrã tem de a anunciar). Sem isto o browser desenhava o seu
   próprio "1." ao lado do círculo numerado de .step-num -- dois números para
   o mesmo passo. Deliberadamente não é `ol { list-style: none }` global:
   dentro do passo do SmartScreen há uma `ol` encaixada cujos números são
   para ler ("1. Mais informações → 2. Executar mesmo assim"). */
.install-steps { display: flex; flex-direction: column; gap: 16px; margin-top: 8px; list-style: none; padding-left: 0; }
.install-steps .step { padding-left: 46px; }


/* ============================================================================
   SITE PÚBLICO — RESPOSTA A ECRÃS PEQUENOS
   ============================================================================
   Its own block, not folded into the existing @media queries above, so the
   site-only rules stay physically inside this marked section. Same
   breakpoints as the rest of the file (980px, 680px, 400px) for one
   consistent set of thresholds project-wide.
   ========================================================================== */

@media (max-width: 980px) {
  .hero { grid-template-columns: 1fr; }
  .hero-card { max-width: 420px; }
  .site-footer-row { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 680px) {
  .site-header-row { flex-wrap: wrap; row-gap: 12px; }
  .site-nav { order: 3; width: 100%; margin-inline: 0; flex-wrap: wrap; justify-content: flex-start; }
  .site-footer-row { grid-template-columns: 1fr; }
}

@media (max-width: 400px) {
  .site-header-actions { flex-wrap: wrap; gap: 10px; }
  .step-list, .point-grid, .feature-list, .plan-grid { grid-template-columns: 1fr; }
}


/* ==========================================================================
   FASE 4 -- os ecrãs que faltavam
   ==========================================================================
   Escritos em ficheiros separados enquanto cinco agentes trabalhavam ao
   mesmo tempo (duas escritas concorrentes neste ficheiro perdem-se sem dar
   erro), e consolidados aqui na integração de 2026-08-06. Uma folha de
   estilo só, como o §9 do desenho exige.
   ========================================================================== */

/* ----- Sessões e detalhe de sessão ----------------------------------------- */

/* Componentes de sessoes — andaime de integração 2026-08-06.
   Escrito por um só agente. Consolidado em clockwitness.css no fim.

   A maior parte do que os dois ecrãs precisam já existe em clockwitness.css:
   .turno-card, .stamps/.stamp, .temp-band, .metric-grid/.metric-card, .badge,
   .data-table/.table-scroll, .empty-state, .notice, .btn. O que falta mesmo
   -- e por isso está aqui -- é o layout dos dois ecrãs à volta desses
   componentes, e a grelha de capturas (§4.4 do desenho: "Grelha de capturas
   | Detalhe de sessão | 1 monitor, N monitores, a carregar, descartado"),
   que não tinha equivalente nenhum. */


/* ============================================================================
   LISTA DE SESSÕES
   ========================================================================== */

.session-notices {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 20px 0 28px;
}

/* O título não traz margem própria (o reset põe margin:0 em h1..h4, de
   propósito), por isso quem vem a seguir é que abre o espaço -- e nesta
   página o que vem a seguir é quase sempre a tabela, que ficava colada ao
   "Sessões" como se fosse a legenda dele. Os avisos acima já se defendiam
   sozinhos; a tabela e o estado vazio não. */
h1.title-l + .table-scroll,
h1.title-l + .empty-state { margin-top: 22px; }

/* A descrição da sessão, quando existe, pendurada por baixo do nome do
   projecto em vez de ocupar uma coluna quase sempre vazia (o "—" que o
   briefing aponta). */
.table-note {
  margin-top: 2px;
  font-size: .8rem;
  color: var(--ink-2);
}


/* ============================================================================
   DETALHE DE SESSÃO
   ========================================================================== */

.session-back { margin-bottom: 18px; }

.session-title-row { margin-bottom: 28px; }
.session-title-row .lede { margin-top: 6px; }

.session-description {
  max-width: 62ch;
  margin-top: 10px;
  color: var(--ink-2);
  font-size: .92rem;
}

/* O formulário de edição da própria descrição (session_detail.html,
   can_edit_description) substitui o parágrafo estático .session-description
   acima -- mesma largura de leitura, para o cabeçalho não saltar de forma
   entre os dois estados. `.field` já vem de clockwitness.css (a mesma classe
   de qualquer outro formulário do dashboard); só a largura e o espaçamento
   junto ao botão são próprios daqui. */
.session-description-form { max-width: 62ch; margin-top: 10px; }
.session-description-form .field { margin-bottom: 10px; }

/* O cartão de turno completo (quem, projecto, carimbos, banda), na sua
   própria linha -- não ao lado do .metric-grid. Foi tentado lado a lado
   primeiro, mas .metric-grid espremido numa coluna estreita já não tem
   largura para as suas 4 colunas de minmax(190px,1fr) (ver a própria regra
   em clockwitness.css): sobra uma célula vazia da cor do rule a meio do
   bloco de números. .metric-grid precisa da largura cheia do .shell, tal
   como em dashboard/today.html, para as 4 colunas encaixarem sem sobra. */
.session-card-row { margin-bottom: 28px; }
.session-card-row .turno-card { max-width: 420px; }

.session-section { margin-bottom: 32px; }
.session-section:last-child { margin-bottom: 0; }

.interval-apps { margin-top: 14px; }


/* ---- Grelha de capturas -----------------------------------------------------
   O componente que faltava por completo em clockwitness.css. Um grupo por
   intervalo -- é ao nível do intervalo que o número de monitores e o estado
   de inactividade fazem sentido, não ao nível da sessão inteira -- com a
   grelha responsiva das suas próprias miniaturas lá dentro. Nunca <table>
   (briefing explícito): miniaturas variam de altura conforme o monitor e uma
   tabela força todas as linhas à mesma grelha rígida de colunas.
   -------------------------------------------------------------------------- */

.interval-block {
  padding: 18px 20px 20px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
}
.interval-block + .interval-block { margin-top: 20px; }

/* A única cor de excepção nesta grelha: um intervalo descartado, ou sem
   prova nenhuma, ganha um filete de argila -- a mesma linguagem que
   .metric-card.needs-action e .notice.needs-action já usam noutros ecrãs --
   nunca o cartão inteiro pintado, e nunca uma cor diferente a inventar um
   segundo significado. Os dois estados partilham a regra porque partilham o
   significado: "este bloco não conta", seja porque a pessoa o recusou, seja
   porque não há prova nenhuma dele. */
.interval-block.is-discarded,
.interval-block.is-without-evidence { border-left: 3px solid var(--clay); }

.interval-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin-bottom: 14px;
  font-size: .86rem;
  color: var(--ink-2);
}
.interval-time { font-size: 1rem; color: var(--ink); }

/* A tira desliza na horizontal, dentro da sua própria caixa -- nunca a
   página inteira (mesma ideia de .table-scroll, mais acima). Com o escalão
   de captura configurável um intervalo pode ter dezenas de capturas; a
   grelha antiga (grid auto-fill, sem tecto) fazia a página crescer na
   vertical sem fim para lhes dar espaço a todas. */
.shot-strip {
  overflow-x: auto;
  padding-bottom: 6px;
}

.shot-grid {
  display: flex;
  gap: 14px;
  width: max-content;
}

.shot-card {
  flex: 0 0 200px;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: var(--r-s);
  background: var(--bg);
}
.shot-card a { display: block; }
.shot-card img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--rule);
}
.shot-caption {
  padding: 7px 10px 9px;
  font-size: .74rem;
  line-height: 1.4;
  color: var(--ink-2);
}
.shot-caption .num { color: var(--ink); }

.shot-empty { margin: 0; font-size: .86rem; color: var(--ink-2); }


/* ============================================================================
   RESPOSTA A ECRÃS PEQUENOS -- mesmos pontos de quebra do resto do ficheiro
   (980px, 680px, 400px), verificação a 400px por fazer na integração (ver
   relatório).
   ========================================================================== */

@media (max-width: 400px) {
  .shot-card { flex-basis: 140px; }
  .interval-block { padding: 16px 16px 18px; }
}

/* ----- Relatórios e Projectos ----------------------------------------- */

/* ============================================================================
   Relatórios e Projectos — andaime de integração 2026-08-06 (Fase 4, agente B)
   ============================================================================
   Escrito por um só agente, para os quatro ecrãs listados no briefing:
   report.html, project_list.html, project_edit.html, project_members.html.
   Só tokens já definidos em clockwitness.css (nenhum valor novo de cor,
   tipo de letra ou raio). Consolidado em clockwitness.css no fim da Fase 4 e
   este ficheiro apagado -- ver docs/superpowers/plans/
   2026-08-06-fase-4-briefing-equipa.md §3.

   Componentes novos, e porquê nenhum dos já existentes servia:

   .filter-bar        -- os filtros de período do relatório. O inventário do
                          briefing (§2) lista-o explicitamente como o
                          componente em falta ("é o componente que falta e
                          que constróis no teu CSS").
   .report-period      -- legenda do intervalo de datas por cima do
                          metric-grid do Resumo; substitui a coluna "Período"
                          que a tabela antiga tinha.
   .report-hint         -- texto secundário solto (nota de inactividade por
                          resolver, legenda das aplicações). A classe `.meta`
                          que isto usava já não existe.
   .report-section      -- ritmo vertical entre as secções do relatório
                          (Resumo / Por projecto / Por colaborador /
                          Aplicações), todas element `.section-label`.
   .report-exports      -- alinhamento dos dois botões de exportação no fim.
   .field-group          -- fieldset com aspecto de `.field`, para o grupo de
                          checkboxes de membros do formulário de criar
                          projecto -- `.field` em si só estiliza
                          input/select/textarea, não uma lista de checkboxes.
   .checkbox-grid/.checkbox-option -- a grelha de checkboxes dentro do
                          `.field-group` acima.
   ========================================================================== */


/* ---- Filtros de período (Relatórios) ---------------------------------------
   Um `.form-card` a envolver isto dá o cartão; esta classe só resolve a
   disposição em linha dos campos e o botão alinhado à base -- .field, em
   pilha vertical por omissão, já trata de cada campo individual.
   -------------------------------------------------------------------------- */

.report-filters {
  margin: 24px 0 32px;
}

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 18px 22px;
}

.filter-bar .field {
  flex: 1 1 160px;
  min-width: 140px;
  margin-bottom: 0;
}

.filter-actions {
  display: flex;
  flex: none;
  gap: 10px;
}

@media (max-width: 400px) {
  .filter-bar { flex-direction: column; align-items: stretch; }
  .filter-bar .field { flex: 1 1 auto; }
  .filter-actions { width: 100%; }
  .filter-actions .btn { flex: 1; }
}


/* ---- Corpo do relatório ----------------------------------------------------- */

/* h1/.title-l não têm margem própria (o reset do clockwitness.css põe
   margin:0 em h1..h4,p de propósito -- ver a cabeça desse ficheiro): quem
   segue o título é que traz o espaço, tal como .today-metrics já faz em
   dashboard/today.html. */
.report-intro { margin-top: 6px; }

.report-period {
  margin: 0 0 18px;
  font-size: .84rem;
  color: var(--ink-2);
}

.report-hint {
  margin-top: 10px;
  font-size: .84rem;
  color: var(--ink-2);
}

.report-section + .report-section {
  margin-top: 40px;
}

.report-exports {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 40px;
}


/* ---- Formulário de criar projecto: grupo de membros -------------------------
   `.field` sozinho não cobre isto -- foi desenhado para um único
   input/select/textarea, e aqui há uma lista inteira de checkboxes dentro de
   um fieldset. Mesmo raio e filete que `.field input`, para não parecer um
   componente à parte.
   -------------------------------------------------------------------------- */

.field-group {
  margin: 0 0 18px;
  padding: 14px 16px 16px;
  border: 1.5px solid var(--rule);
  border-radius: var(--r-s);
}

.field-group legend {
  padding: 0 4px;
  font-size: .82rem;
  font-weight: 600;
  color: var(--ink);
}

.field-group .help { margin: 2px 0 10px; font-size: .78rem; color: var(--ink-2); }

.checkbox-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-top: 6px;
}

.checkbox-option {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .88rem;
  color: var(--ink);
}


/* ---- Projectos: lista e formulários ------------------------------------------ */

/* Mensagens de sucesso (django.contrib.messages) -- `.notice` já existe;
   isto só dá ritmo vertical a uma pilha delas entre o título e o resto. */
.flash-messages {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 18px 0 24px;
}

.project-panel { margin: 24px 0 28px; }
.project-panel .title-m { margin-bottom: 16px; }

/* Formulário de uma coluna (editar projecto, associar pessoa a um projecto):
   o `.form-card` já existente fica largo de mais para dois ou três campos
   sozinhos, por isso limitamos a largura aqui em vez de inventar um segundo
   cartão. */
/* Variante estreita própria: .is-narrow ficou com 640px (Definições e
   Equipa, formulários com mais campos). Dois ficheiros a definir a mesma
   classe com larguras diferentes davam a este ecrã a largura do outro,
   sem erro e sem ninguém poder ver -- os dois agentes escreveram-na ao
   mesmo tempo. */
.form-card.is-compact { max-width: 460px; margin-top: 24px; }

.back-link {
  display: inline-block;
  margin: 10px 0 18px;
  font-size: .88rem;
  color: var(--ink-2);
  text-decoration: none;
}
.back-link:hover { color: var(--ink); }


/* ---- Resposta a ecrãs pequenos ------------------------------------------------
   Verificação a 400px por fazer na integração (ver relatório da tarefa) --
   estas regras seguem os mesmos pontos de quebra do resto do ficheiro
   (980px, 680px, 400px).
   -------------------------------------------------------------------------- */

@media (max-width: 680px) {
  .report-exports { flex-direction: column; }
  .report-exports .btn { width: 100%; }
}

/* ----- Equipa, Definições e autenticação ----------------------------------------- */

/* ============================================================================
   Equipa, Definições e autenticação — andaime de integração 2026-08-06
   ============================================================================
   Escrito por um só agente (C). Consolidado em clockwitness.css no fim pelo
   engenheiro que integra -- ver docs/superpowers/plans/
   2026-08-06-fase-4-briefing-equipa.md §3. Aditivo apenas: nenhum token nem
   componente de clockwitness.css é redefinido aqui. Cada nome de classe é
   específico ao domínio destes ecrãs, pela mesma razão que o próprio
   clockwitness.css avisa contra nomes genéricos soltos.
   ========================================================================== */


/* ----------------------------------------------------------------------------
   Cartão de autenticação
   ----------------------------------------------------------------------------
   Login, recuperação de password, aceitar convite, convite indisponível: a
   mesma moldura em todos -- um `.form-card` (já existe) centrado no ecrã, em
   vez de cada página reinventar a sua própria margem. `.auth-shell` é só o
   posicionamento; `.auth-card` só a largura -- a aparência (fundo, sombra,
   bordo) continua inteiramente a cargo de `.form-card`.
   -------------------------------------------------------------------------- */

.auth-shell {
  display: flex;
  justify-content: center;
  padding-block: clamp(32px, 8vw, 88px);
}

.auth-card { width: 100%; max-width: 420px; }

.auth-card .eyebrow { margin-bottom: 10px; }
.auth-card .title-m { margin-bottom: 4px; }
.auth-card .lede { max-width: none; margin-bottom: 22px; font-size: .92rem; }

.auth-card form .btn-primary { width: 100%; margin-top: 6px; }

.auth-card-foot {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
  font-size: .86rem;
  color: var(--ink-2);
}
.auth-card-foot a { text-decoration: underline; }


/* ----------------------------------------------------------------------------
   Definições -- cartão de formulário estreito, agrupado por assunto
   ----------------------------------------------------------------------------
   `.form-card` sozinho ocupa a largura do `.shell` (1280px); um formulário de
   texto corrido nunca deve chegar lá. `.is-narrow` é só a largura máxima --
   tudo o resto continua a vir de `.form-card`.
   -------------------------------------------------------------------------- */

.form-card.is-narrow { max-width: 640px; }

.form-card .section-label { margin-top: 26px; }
.form-card .section-label:first-child { margin-top: 0; }

/* Uma caixa de selecção (BooleanField) não é um campo de texto: a etiqueta
   fica ao lado, não por cima, e o próprio controlo não deve esticar para
   100% de largura como `.field input[type="text"]` faz. */
.field-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.field-check input[type="checkbox"] {
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  accent-color: var(--accent);
}
.field-check label {
  margin-bottom: 0;
  font-weight: 600;
  cursor: pointer;
}
/* input + uma segunda coluna (label, help, erros) -- não precisa de
   indentação manual: o próprio flex já alinha a coluna de texto depois da
   caixa de selecção. */
.field-check > div { flex: 1; }


/* ----------------------------------------------------------------------------
   Avisos empilhados (mensagens do Django + alertas persistentes de uma página)
   -------------------------------------------------------------------------- */

.stacked-notices {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 20px 0 28px;
}

/* Um parágrafo de contexto por baixo de um título de secção -- mais discreto
   que `.lede` (que é para texto de destaque, tipo herói), mais pequeno que o
   corpo normal. Usado para "a pessoa recebe um email..." e "'reenviar' gera
   uma ligação nova...". */
.section-note {
  margin: -6px 0 18px;
  max-width: 62ch;
  font-size: .86rem;
  color: var(--ink-2);
}


/* ----------------------------------------------------------------------------
   Tabela de equipa -- pessoa (nome, com o email como linha secundária)
   ----------------------------------------------------------------------------
   Uma só célula em vez de duas colunas separadas: quando há nome, o email é
   só contexto, não outro dado a ler à parte. Sem nome (o defeito reportado
   desde a sessão 012), o email sobe e é a única linha -- nunca um traço.
   -------------------------------------------------------------------------- */

.person-name { font-weight: 600; }
.person-email { margin-top: 2px; font-size: .82rem; color: var(--ink-2); }

/* O papel de alguém, e por baixo, só quando aplicável, o aviso de que essa
   pessoa não tem projecto onde registar tempo -- nunca o emoji ⚠ que aqui
   estava antes. */
.role-flag { margin-top: 6px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.role-flag a { font-size: .82rem; text-decoration: underline; }


/* ----------------------------------------------------------------------------
   Convites -- terceiro estado do badge
   ----------------------------------------------------------------------------
   `.badge` já tem `.is-active`, `.is-pending` e `.is-problem`
   (clockwitness.css); falta "expirado", que o inventário de componentes (§4.4
   do desenho) lista como estado próprio e distinto de "pendente" -- um
   convite expirado não precisa de acção correctiva como a falha de entrega
   (`.is-problem`, argila), nem está à espera de ser aberto (`.is-pending`,
   tracejado): já não pode ser aberto, ponto final. Cinzento neutro, a mesma
   família visual do `.badge` sem modificador que a tabela de pessoas usa para
   "inactivo".
   -------------------------------------------------------------------------- */

.badge.is-expired { border-color: var(--rule); color: var(--ink-2); background: var(--rule); }

/* A explicação por baixo do badge de falha de entrega -- o badge diz o
   estado numa palavra, esta linha diz o que aconteceu e o que fazer. */
.invite-note { margin-top: 5px; font-size: .78rem; color: var(--ink-2); }

.invite-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.invite-actions form { display: inline-flex; }
/* Um botão sem moldura própria por cima de um `.btn-quiet`/`.btn-ghost` já
   existente -- só para o formulário de uma linha (csrf + hidden inputs) não
   introduzir espaço a mais à volta do botão que contém. */
.invite-actions form .btn { padding: 6px 12px; }


/* ============================================================================
   RESPOSTA A ECRÃS PEQUENOS
   ============================================================================
   Mesmos pontos de quebra do resto do sistema (980px, 680px, 400px). */

@media (max-width: 400px) {
  .auth-card { max-width: 100%; }
  .role-flag { flex-direction: column; align-items: flex-start; gap: 4px; }
}

/* ----- Página do agente e guia de instalação ----------------------------------------- */

/* Componentes de agente-guia — andaime de integração 2026-08-06.
   Escrito por um só agente. Consolidado em clockwitness.css no fim.

   A maior parte do guia (templates/_agent_install_guide.html) usa
   componentes que já existem: .section-label, .install-steps/.step/
   .step-num, .notice/.notice.needs-action, .point-grid/.point-card, .btn.
   O que falta mesmo é a moldura de captura de ecrã com legenda (o guia é a
   única página do projecto com screenshots dentro do corpo do texto) e a
   legenda dos três estados do ícone da bandeja -- ver docs/superpowers/
   specs/2026-08-06-fluxo-descarregar-instalar.md §7, decisão 4. */


/* ---- Largura de leitura --------------------------------------------------
   .install-steps e .faq-list herdam a largura toda do .shell (1280px) por
   omissão -- bom para uma lista curta de 3 passos ("Como funciona" no
   site), ilegível para um guia de 7 passos com parágrafos. O antigo guia
   já limitava a mesma coisa com `.guide { max-width: 720px }`.
   -------------------------------------------------------------------------- */

.agent-guide .install-steps,
.agent-guide .faq-list {
  max-width: 680px;
}

/* Identificadores dentro do texto corrido -- nome do instalador, domínio --
   são exactamente o caso que §4.2 do desenho reserva para DM Mono. */
.agent-guide code {
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--bg);
  font-family: var(--f-mono);
  font-size: .88em;
}


/* ============================================================================
   MOLDURA DE CAPTURA DE ECRÃ COM LEGENDA
   ============================================================================
   Um <figure>: a imagem com um filete e sombra suave (o mesmo tratamento que
   .turno-card e .plan-card já dão a qualquer superfície elevada), a legenda
   por baixo em texto pequeno. `.is-wide` para as capturas de ecrãs cheios
   (Chrome, SmartScreen); sem o modificador para janelas mais estreitas da
   própria aplicação.
   ========================================================================== */

.agent-guide-shot {
  margin: 16px 0;
  max-width: 440px;
}
.agent-guide-shot.is-wide { max-width: 620px; }
.agent-guide-shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
  box-shadow: var(--shadow-soft);
}
.agent-guide-shot figcaption {
  margin-top: 8px;
  font-size: .82rem;
  color: var(--ink-2);
}


/* ============================================================================
   LEGENDA DOS ESTADOS DO ÍCONE DA BANDEJA
   ============================================================================
   Os três estados reais (CaptureState.Recording/.Paused/.Stopped) têm hoje
   ícones fora do sistema Turno (azul com ponto vermelho / azul com ponto
   cinzento / cinzento sem ponto -- ver o texto da legenda, que descreve o
   que a pessoa vai mesmo ver). As bolinhas aqui não copiam essas cores: "a
   gravar" usa --accent (a mesma leitura de "activo" que .turno-status.is-
   live já usa), nunca --clay nem vermelho de alarme -- este produto não
   pinta ninguém de vermelho por estar a trabalhar. "Parado" é um anel vazio,
   a mesma metáfora de ausência que .temp-band .is-pause já usa com --rule.
   ========================================================================== */

.tray-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  margin: 16px 0;
  padding: 14px 18px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
  list-style: none;
}
.tray-legend-item {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  max-width: 30ch;
  font-size: .86rem;
  color: var(--ink-2);
}
.tray-legend-item strong { color: var(--ink); }

.tray-legend-dot {
  flex: none;
  width: 11px;
  height: 11px;
  margin-top: .2em;
  border-radius: 50%;
}
.tray-legend-dot.is-recording { background: var(--accent); }
.tray-legend-dot.is-paused { background: var(--ink-2); }
.tray-legend-dot.is-stopped { background: transparent; border: 2px solid var(--ink-2); }


/* ============================================================================
   PERGUNTAS FREQUENTES
   ============================================================================
   Não havia nenhum componente de FAQ no sistema ainda (nenhuma outra página
   construída até agora tinha uma). <dl> com um <div> por par -- válido em
   HTML5 -- em vez de .qa inventada à mão do guia antigo.
   ========================================================================== */

.faq-list {
  display: flex;
  flex-direction: column;
  gap: 22px;
  margin-top: 8px;
}
.faq-list dt { margin-bottom: 4px; font-weight: 600; }
.faq-list dd { margin: 0; font-size: .9rem; color: var(--ink-2); }

.agent-guide-faq {
  margin-top: 48px;
  padding-top: 32px;
  border-top: 1px solid var(--rule);
}


/* ============================================================================
   PÁGINA /app/agente/ — botão real e âncoras
   ============================================================================ */

.agent-download-cta { margin: 28px 0 8px; }
.agent-download-cta-note { margin-top: 10px; font-size: .84rem; color: var(--ink-2); }
.agent-download-cta .notice { max-width: 58ch; margin-top: 16px; }

.agent-download-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 40px;
}


@media (max-width: 400px) {
  .tray-legend-item { max-width: none; }
}

/* ----- Site público ----------------------------------------- */

/* Componentes de site-publico — andaime de integração 2026-08-06.
   Escrito por um só agente. Consolidado em clockwitness.css no fim. */

/* ----------------------------------------------------------------------
   AVISO COM VÁRIAS FRASES -- variante de .notice (clockwitness.css)
   ----------------------------------------------------------------------
   O .notice original foi desenhado para uma linha só (ver os usos em
   Sessões/Hoje). "/descarregar/" precisa de um aviso persistente com um
   título, vários parágrafos e um botão -- "Ainda não tem conta?" -- e o
   reset global zera a margem de h1..h4 e p (clockwitness.css:158), por
   isso, sem isto, tudo ficava colado. Regra pequena, ao lado do
   componente que estende, não um componente novo. */
/* h2 acrescentado na revisão adversarial da Tarefa A (sessão 018):
   dashboard/dia.html usa `.notice` para o estado de fuso inválido, cujo
   título passou de <p> a <h2> (é a única secção do ecrã nesse estado --
   <h3> repetiria o defeito que esta tarefa existe para corrigir, um salto
   directo de h1 para h3). site/download.html continua a usar <h3> aqui
   porque o seu aviso vive dentro de uma secção com <h2> própria -- os dois
   níveis são legítimos consoante o que precede o aviso no documento. Prova
   varrida ao produto inteiro nessa revisão: dia.html:41 é o ÚNICO `.notice`
   com um <h2> lá dentro -- é por isso que o selector pode ganhar o h2 sem
   afectar download.html, que continua só a bater no h3.

   Os 10px do espaço título→corpo em dia.html MUDARAM DE SÍTIO, não de
   valor: com <p class="title-s"> o título era mais um <p>, por isso
   `.notice p + p` (a regra a seguir) dava esse espaço como margin-top do
   corpo. Com <h2> essa combinação deixa de bater no corpo -- `.notice p +
   p` agora só liga o corpo ao <p> do botão de definições, quando existe --
   e é esta linha, margin-bottom no título, que passa a dar o mesmo espaço.
   Resultado visual idêntico, mecanismo diferente. */
.notice h2, .notice h3 { margin-bottom: 10px; }
.notice p + p { margin-top: 10px; }
.notice p + .btn { margin-top: 16px; }


/* ----------------------------------------------------------------------
   DIAGRAMA DE AUTO-ALOJAMENTO -- página de Segurança e privacidade
   ----------------------------------------------------------------------
   Pedido explicitamente pelo desenho (§6 da spec do site: "diagrama de
   auto-alojamento") e que não existia nenhum componente pronto para isto.
   Três nós ligados por um filete -- o agente no computador do
   colaborador, a escolha de onde os dados ficam, e o painel do gestor --
   sem setas nem iconografia, só caixas e o filete --rule já usado em toda
   a folha de estilo.
   ---------------------------------------------------------------------- */
.hosting-diagram {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: stretch;
  gap: 0;
  margin-top: 28px;
}
.hosting-node {
  padding: 20px 20px 22px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
}
.hosting-node .eyebrow { margin-bottom: 8px; }
.hosting-node p { font-size: .88rem; color: var(--ink-2); }
.hosting-node p + p { margin-top: 10px; }
.hosting-link {
  align-self: center;
  width: 28px;
  height: 1px;
  background: var(--rule);
  margin-inline: 6px;
}
.hosting-options { display: flex; flex-direction: column; margin-top: 4px; }
.hosting-option { padding-top: 12px; border-top: 1px solid var(--rule); }
.hosting-option:first-child { padding-top: 0; border-top: none; }
.hosting-option h4 { font-size: .92rem; margin-bottom: 4px; }
.hosting-option p { margin: 0; }

@media (max-width: 720px) {
  .hosting-diagram { grid-template-columns: 1fr; gap: 14px; }
  .hosting-link { width: 1px; height: 20px; margin-inline: auto; }
}


/* ============================================================================
   FASE — O DIA DE TRABALHO
   ============================================================================
   docs/superpowers/specs/2026-08-12-dia-interface.md
   Aditivo, com três excepções enumeradas em §6.2 desse documento (defeitos de
   contraste de --clay como texto, resolvidos por --clay-ink, D10).
   ========================================================================== */

/* ---- Tokens novos ----------------------------------------------------------
   Um segundo bloco :root, e não uma reescrita do primeiro (linha 94): o
   padrão desta folha, desde a Fase 3, é que cada fase acrescenta a sua
   secção sem tocar nas anteriores. Nenhuma propriedade custom aqui redefine
   uma já existente -- são todas novas (--clay-ink, --s-*, --side-w) --, por
   isso um segundo :root não compete com o primeiro, só o estende.
   -------------------------------------------------------------------------- */

:root {
  /* Argila de TEXTO. --clay dá 3,94:1 sobre --surface e 3,14:1 sobre
     --clay-pale: chega para um filete ou um preenchimento, não chega para
     texto de 11px. Mesma cor de excepção, escurecida até passar AA. --clay
     pinta superfícies; --clay-ink escreve; --clay-pale fala sobre fundo
     escuro. Rácios medidos e confirmados (sRGB, WCAG 2.x): 6,37:1 sobre
     --surface, 5,54:1 sobre --bg, 5,08:1 sobre --clay-pale. D10. */
  --clay-ink: #8F4630;

  /* Escala de espaçamento, 10 degraus. Não é uma grelha de 4px importada de
     fora -- é a linha de festo do que este ficheiro já faz: os cinco valores
     soltos mais frequentes na folha (6, 10, 14, 18, 22) já formam a escada
     de +4 do meio da tabela. Normativa para componentes NOVOS; nenhum
     componente existente é reescrito para a cumprir. */
  --s-2xs:  2px;   /* filetes internos, separadores dentro de uma banda */
  --s-xs:   4px;   /* entre irmãos que se lêem como um objecto só */
  --s-s:    6px;   /* rótulo → valor */
  --s-m:   10px;   /* dentro de um controlo, entre controlos irmãos */
  --s-l:   14px;   /* entre elementos de um componente; goteira da grelha de capturas */
  --s-xl:  18px;   /* entre componentes dentro de um bloco */
  --s-2xl: 22px;   /* almofada de cartão; título → conteúdo */
  --s-3xl: 30px;   /* entre blocos de uma secção */
  --s-4xl: 44px;   /* entre secções */
  --s-5xl: 72px;   /* fundo da página */

  /* Largura da barra lateral -- usada por .app-frame e .sidebar. */
  --side-w: 256px;
}


/* ----------------------------------------------------------------------------
   A RAMPA -- mapeamento de cores e a forma isolada
   ----------------------------------------------------------------------------
   §2.4 da spec de interface pede UM mapeamento só, partilhado entre
   `.temp-band`, `.daybar-block` e `.ramp-chip`, para que os três sítios nunca
   possam divergir. Este ficheiro já tem esse mapeamento para `.temp-band`
   (secção "CARTÃO DE TURNO", linhas 472-476) e a fronteira desta tarefa
   proíbe tocar em regras existentes fora das três (+ uma) que a própria spec
   de interface enumera em §6.2 -- `.temp-band .act-N` não está nessa lista.
   Reescrever aqui as mesmas cinco regras para `.temp-band` criaria a
   "segunda tabela" que a spec explicitamente rejeita (duas fontes da mesma
   verdade); por isso este bloco cobre só os DOIS sítios novos, e o
   comentário fica a marcar a decisão para quem vier a seguir. Ver "Onde
   discordei" no relatório desta tarefa. */
.daybar-block.act-1, .ramp-chip.act-1 { background: var(--act-1); }
.daybar-block.act-2, .ramp-chip.act-2 { background: var(--act-2); }
.daybar-block.act-3, .ramp-chip.act-3 { background: var(--act-3); }
.daybar-block.act-4, .ramp-chip.act-4 { background: var(--act-4); }
.daybar-block.act-5, .ramp-chip.act-5 { background: var(--act-5); }

/* A rampa como objecto ISOLADO ganha um anel de tinta: sem ele, act-1 sobre
   --surface mede 1,22:1 e o chip desaparece do cartão. O anel mede 5,95:1
   contra --surface e 4,86:1 contra o próprio act-1. */
.ramp-chip {
  flex: none;
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  box-shadow: inset 0 0 0 1px var(--ink-2);
}
.daybar-legend .ramp-chip { width: 13px; height: 13px; }

/* O quinto estado do vocabulário da banda: "sem o agente a correr" (§4.3 do
   desenho -- relógio menos registado, pausa, sem prova e descartado). É
   ausência de dados, não ausência de trabalho -- por isso o mesmo fundo do
   cartão que o envolve, não --rule nem --clay-pale, que já significam outra
   coisa. Aditivo: `.temp-band` em si (fundo, altura, gap) não é tocado. */
.temp-band .is-off { background: var(--surface); }


/* ----------------------------------------------------------------------------
   .app-frame / .sidebar* / .app-page -- a moldura
   ----------------------------------------------------------------------------
   Substitui `.app-nav` como navegação principal do backoffice para quem
   vive dentro de `.app-frame`. `.app-nav` e a família continuam a existir,
   inalteradas, para quem ainda não migrou (§6.3 da spec de interface).
   -------------------------------------------------------------------------- */

.app-frame {
  display: grid;
  grid-template-columns: var(--side-w) minmax(0, 1fr);
  min-height: 100vh;
}

/* minmax(0, 1fr) e não 1fr: o mínimo automático de 1fr é min-content, e a
   grelha de capturas (min-width 640px) esticava a pista -- a página inteira
   rolava na horizontal em vez de a tira rolar dentro da sua caixa. */

.sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--s-xl);
  padding: var(--s-2xl) var(--s-l) var(--s-xl);
  background: var(--ink);
  color: var(--bg);
}

.sidebar .wordmark { padding: var(--s-xs) var(--s-l) var(--s-2xs); text-decoration: none; }
.sidebar .wordmark .hole { border-color: var(--accent-pale); }
/* --accent sobre --ink mede 2,31:1: o anel da marca desaparecia. --accent-pale
   mede 12,25:1. Mesma razão, mesma solução que .app-nav já usa para o foco. */

.sidebar-nav { display: flex; flex-direction: column; gap: var(--s-2xs); }

.sidebar-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-m);
  padding: 9px var(--s-l);
  border-radius: var(--r-s);
  font-size: .93rem;
  text-decoration: none;
  color: rgba(237, 231, 223, .74);            /* 7,96:1 sobre --ink, confirmado */
  transition: background .15s ease, color .15s ease;
}
.sidebar-link:hover { color: var(--bg); background: rgba(237, 231, 223, .08); }
.sidebar-link[aria-current="page"] {
  color: var(--ink);                           /* 12,25:1 sobre --accent-pale */
  background: var(--accent-pale);
  font-weight: 600;
}
.sidebar-link .chev { font-size: .7rem; opacity: .55; }

/* A excepção, sobre fundo escuro, fala em --clay-pale: --clay mede 3,96:1
   (falha a 11px) e --clay-ink mede 2,44:1. Ver a secção de tokens acima. */
.sidebar-count {
  font-family: var(--f-mono);
  font-size: .72rem;
  font-variant-numeric: tabular-nums;
  color: var(--clay-pale);                     /* 12,42:1 sobre --ink */
}

.sidebar-sub {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: var(--s-xs) 0 var(--s-m) var(--s-l);
  padding-left: var(--s-m);
  border-left: 1px solid rgba(237, 231, 223, .16);
}
.sidebar-person {
  display: flex;
  align-items: center;
  gap: var(--s-m);
  padding: 7px var(--s-m);
  border-radius: var(--r-s);
  font-size: .85rem;
  text-decoration: none;
  color: rgba(237, 231, 223, .62);             /* 5,99:1 sobre --ink, confirmado */
}
.sidebar-person:hover { color: var(--bg); background: rgba(237, 231, 223, .07); }
.sidebar-person[aria-current="true"] { color: var(--accent-pale); font-weight: 600; }
.sidebar-person .st {
  flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: rgba(237, 231, 223, .28);
}
.sidebar-person .st.is-live { background: var(--accent-pale); }

.sidebar-foot { margin-top: auto; display: flex; flex-direction: column; gap: var(--s-l); }
.sidebar-user { display: flex; align-items: center; gap: var(--s-m); font-size: .84rem; color: rgba(237, 231, 223, .62); }
.sidebar-user .person-avatar { width: 32px; height: 32px; background: rgba(237, 231, 223, .14); color: var(--bg); font-size: .74rem; }

/* --accent sobre --ink mede 2,31:1, abaixo do mínimo de 3:1 para um indicador
   de foco: um anel azeitona é quase invisível sobre a barra escura. --bg
   mede 13,54:1. Mesma correcção que .app-nav já tem no ficheiro. */
.sidebar a:focus-visible,
.sidebar button:focus-visible { outline-color: var(--bg); }

.app-main { min-width: 0; }

.app-page {
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(var(--s-2xl), 3vw, var(--s-4xl));
  padding-block: var(--s-3xl) var(--s-5xl);
}
/* `.app-page`, e não `.shell`: `.shell` usa clamp(20px, 5vw, 64px), calculado
   contra a JANELA e não contra a coluna. Dentro de uma moldura com 256px de
   barra lateral, 64px de goteira desalinha o conteúdo do resto do sistema.
   `.shell` não se altera -- continua a servir o site público e os ecrãs que
   não vivem dentro de `.app-frame`. */

@media (max-width: 980px) {
  .app-frame { grid-template-columns: minmax(0, 1fr); }
  .sidebar {
    position: static; height: auto; overflow: visible;
    flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--s-m);
  }
  .sidebar-nav { flex-direction: row; flex-wrap: wrap; flex: 1; }
  .sidebar-sub, .sidebar-user { display: none; }
  .sidebar-foot { margin: 0; flex-direction: row; align-items: center; }
}


/* ----------------------------------------------------------------------------
   .date-bar -- a barra de data
   ----------------------------------------------------------------------------
   O componente que hoje só existe em Relatórios (.filter-bar, mais acima),
   promovido a navegação temporal do backoffice inteiro. D3: a data vive no
   URL, nunca em sessão -- este componente é só apresentação.
   -------------------------------------------------------------------------- */

.date-bar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--s-xl);
  flex-wrap: wrap;
  padding: var(--s-l) clamp(var(--s-2xl), 3vw, var(--s-4xl));
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
  box-shadow: var(--shadow-soft);
}

.date-nav { display: flex; align-items: center; gap: var(--s-s); }

.date-step {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: 1.5px solid var(--rule);
  border-radius: var(--r-s);
  background: var(--bg);
  color: var(--ink);
  text-decoration: none;
  line-height: 1;
}
.date-step:hover { border-color: var(--ink-2); }
/* Há chão e há tecto. Sem eles anda-se para trás indefinidamente por ecrãs
   vazios idênticos, sem forma de saber se é "não há nada" ou "sou eu". */
.date-step.is-disabled { opacity: .35; pointer-events: none; }

.date-current {
  min-width: 15.5rem;
  padding-inline: var(--s-xs);
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -.01em;
}
.date-current small {
  display: block;
  font-family: var(--f-mono);
  font-weight: 400;
  font-size: .7rem;
  letter-spacing: .04em;
  color: var(--ink-2);                        /* 5,95:1 sobre --surface */
}

.presets { display: flex; gap: var(--s-xs); flex-wrap: wrap; }
.preset {
  padding: 7px var(--s-l);
  border: 1.5px solid transparent;
  border-radius: 999px;
  font-size: .84rem;
  text-decoration: none;
  color: var(--ink-2);
}
.preset:hover { color: var(--ink); background: var(--bg); }
.preset[aria-current="page"] {
  background: var(--accent-pale);
  border-color: var(--accent);
  color: var(--accent-2);                     /* 7,62:1 sobre --accent-pale */
  font-weight: 600;
}

.date-bar-right { margin-left: auto; display: flex; align-items: center; gap: var(--s-m); }

.select-field {
  padding: var(--s-m) var(--s-l);
  border: 1.5px solid var(--rule);
  border-radius: var(--r-s);
  background: var(--bg);
  font-family: var(--f-body);
  font-size: .86rem;
  color: var(--ink);
}

@media (max-width: 680px) {
  .date-step { width: 40px; height: 40px; }
  .date-current { min-width: 0; }
  .date-bar-right { margin-left: 0; width: 100%; }
  .date-bar-right .select-field { flex: 1; }
}


/* ----------------------------------------------------------------------------
   .strip-days -- a tira do mês
   -------------------------------------------------------------------------- */

.strip-days { display: flex; gap: var(--s-xs); overflow-x: auto; padding: var(--s-xs) 0 var(--s-m); }

.strip-day {
  flex: 0 0 auto;
  min-width: 40px;
  padding: 7px var(--s-s) var(--s-s);
  border: 1.5px solid transparent;
  border-radius: var(--r-s);
  text-align: center;
  text-decoration: none;
  color: inherit;
}
.strip-day:hover { background: var(--surface); border-color: var(--rule); }
.strip-day b { display: block; font-family: var(--f-mono); font-weight: 500; font-size: .95rem; font-variant-numeric: tabular-nums; }
.strip-day span { display: block; font-size: .66rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-2); }

/* Um sábado não é uma excepção que pede acção. Já foi argila, e o mesmo
   ecrã passou a ter argila a significar duas coisas. */
.strip-day.is-weekend { background: rgba(216, 207, 195, .35); }

.strip-day[aria-current="date"] { background: var(--ink); border-color: var(--ink); }
.strip-day[aria-current="date"] b,
.strip-day[aria-current="date"] span { color: var(--bg); }   /* 13,54:1 */

.strip-day.is-future { opacity: .3; pointer-events: none; }

/* Escala ABSOLUTA, tecto de 10h -- nunca relativa ao máximo do mês daquela
   pessoa: com escala relativa, trocar de pessoa na barra lateral repinta a
   escala e a mesma altura significa 4h numa e 9h noutra.
   A linha de base é DESENHADA: sem ela, 1px separa "não trabalhou" de
   "trabalhou uma hora". */
.strip-bar {
  display: flex; align-items: flex-end; justify-content: center;
  height: 26px; margin-top: 5px;
  border-bottom: 1px solid var(--rule);
}
.strip-bar i {
  display: block; width: 9px;
  border-radius: 2px 2px 0 0;
  background: var(--accent);                  /* 5,86:1 sobre --bg */
}
.strip-bar i.is-empty { display: none; }
.strip-bar i.is-over { border-top: 2px solid var(--ink); }   /* passou do tecto de 10h */

/* O tempo sem prova fica SOB a linha de base: literalmente fora do total,
   impossível de ler como parte da altura da barra. */
.strip-day.has-gap { box-shadow: inset 0 -2px 0 var(--clay); }

/* Tempo manual: SOBRE a linha de topo, não a de base -- já está DENTRO da
   altura da barra (D9 só exclui falta de prova, não este modo), --ink-2 e
   não --clay porque não é uma excepção que pede acção, é um facto a
   assinalar (a mesma família visual do crachá "Manual" tracejado de
   session_list.html). Um dia com os dois marcadores mostra ambos -- linhas
   em bordos opostos, nunca uma a substituir a outra. */
.strip-day.has-manual { box-shadow: inset 0 2px 0 var(--ink-2); }
.strip-day.has-gap.has-manual {
  box-shadow: inset 0 2px 0 var(--ink-2), inset 0 -2px 0 var(--clay);
}

.strip-day[aria-current="date"] .strip-bar { border-bottom-color: var(--ink-2); }
.strip-day[aria-current="date"] .strip-bar i { background: var(--accent-pale); }


/* ----------------------------------------------------------------------------
   .day-hero -- o herói do dia
   -------------------------------------------------------------------------- */

.day-hero {
  display: flex;
  flex-direction: column;
  gap: var(--s-xs);
  padding: var(--s-2xl) var(--s-2xl) var(--s-xl);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
}
.day-hero .eyebrow { margin-bottom: var(--s-2xs); }

/* Display proporcional: é um número isolado, sem vizinhos com quem se
   alinhar -- o único sítio do ecrã onde este papel se aplica. */
.day-hero-value {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(2.4rem, 5vw, 3.2rem);
  line-height: 1;
  letter-spacing: -.02em;
}
.day-hero-note { margin-top: var(--s-s); font-size: .92rem; color: var(--ink-2); }
/* "a decorrer" mede 9,69:1 sobre --surface (a spec de interface regista
   7,0:1; medido aqui em WCAG 2.x com os hex do token dá 9,69:1 -- acima do
   que estava escrito, portanto ainda AAA folgado. Corrigido nesta folha para
   não repetir um número desactualizado). */
.day-hero-note b.ainda { color: var(--accent-2); font-weight: 600; }
.com-prova { font-size: .84rem; color: var(--ink-2); }


/* ----------------------------------------------------------------------------
   .daybar* -- a linha do dia
   ----------------------------------------------------------------------------
   A peça central do ecrã novo. Quatro camadas empilhadas, todas na mesma
   escala horizontal: blocos → réguas de hora → colchetes de arranque (e
   buracos) → legenda.
   -------------------------------------------------------------------------- */

.daybar {
  padding: var(--s-2xl) var(--s-2xl) var(--s-xl);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-m);
}

.daybar-track {
  position: relative;
  height: 44px;
  border-radius: var(--r-s);
  background: var(--bg);
  overflow: hidden;
}

/* Sem cursor:pointer: até à revisão adversarial de 2026-08-12 estes blocos
   eram <button>, prometiam um clique que nenhum tratador respondia -- dez
   por dia, todos apontando para nada. Agora são <span> (ver
   _dia_daybar.html) e a moldura não pode continuar a dizer "carrega aqui"
   por um elemento que nem sequer se pode focar. */
.daybar-block {
  position: absolute;
  top: 0; bottom: 0;
  padding: 0;
  border: 0;
  background: transparent;
}

/* A rampa como figura ISOLADA precisa de anel: act-1 mede 1,06:1 contra a
   pista, act-2 1,45:1, act-3 2,32:1 -- os três abaixo do limiar de 3:1. O
   anel de --ink-2 mede 5,17:1 contra a pista e 4,86:1 contra o próprio
   act-1, e separa blocos vizinhos de degraus próximos de caminho. */
.daybar-block.act-1,
.daybar-block.act-2,
.daybar-block.act-3,
.daybar-block.act-4,
.daybar-block.act-5 { box-shadow: inset 0 0 0 1px var(--ink-2); }

/* PAUSA: filete de 3px a meia altura, não bloco cheio. É ausência, não
   intensidade -- e --ink-2 SÓLIDO, não a 50%: a 50% mede 2,04:1 contra a
   pista, abaixo do limiar de 3:1 para um indicador não textual. */
.daybar-block.is-pause {
  top: 50%; bottom: auto;
  height: 3px;
  transform: translateY(-50%);
  background: var(--ink-2);                   /* 5,17:1 sobre --bg */
  box-shadow: none;
}

/* SEM PROVA: moldura vazia -- SEM preenchimento nenhum, ao contrário da
   versão anterior (background: var(--clay-pale)), que a revisão adversarial
   de 2026-08-12 apanhou no ecrã: convertida a cinzento mede 222, contra os
   225 de .act-1 -- delta de 3 em 255, o mesmo rectângulo a preto e branco.
   São precisamente os dois estados que este produto existe para separar (um
   conta para o total do dia, o outro fica fora dele, D9), e um comentário
   que já dizia "moldura vazia" descrevia um bloco cheio.

   Aqui a distinção passa a ser de FORMA, não de tom: um contorno sem
   preenchimento deixa ver a pista (--bg) por dentro; um bloco cheio não
   deixa ver nada. Essa diferença não depende de cor nenhuma -- sobrevive a
   filter:grayscale(1), a uma impressora a preto e branco, ou a quem não
   distingue --act-1 de --clay-pale por outra razão qualquer. */
.daybar-block.is-without-evidence {
  background: transparent;
  box-shadow: inset 0 0 0 2px var(--clay);    /* 3,96:1 sobre a pista (--bg) */
}

/* DESCARTADO: recusa activa, não ausência. Mesma trama que .temp-band já usa
   para .is-discard. */
.daybar-block.is-discard {
  background-color: var(--clay-pale);
  background-image: repeating-linear-gradient(-45deg, var(--clay) 0 2px, transparent 2px 5px);
  box-shadow: inset 0 0 0 1.5px var(--clay);
}

/* O anel global do :focus-visible tem offset 3px e a pista tem
   overflow:hidden -- o anel ficava cortado. Aqui desenha-se PARA DENTRO, e
   em --ink porque --accent mede 1,50:1 contra act-4 e 1,33:1 contra act-5.
   O halo interior de --surface garante 15,58:1 contra o anel, seja qual for
   o preenchimento. O outline não é removido -- muda de cor e de sentido. */
.daybar-block:focus-visible {
  outline: 2.5px solid var(--ink);
  outline-offset: -2.5px;
  box-shadow: inset 0 0 0 5px var(--surface);
  z-index: 2;
}
.daybar-block:hover { z-index: 1; }

.daybar-ticks { position: relative; height: 22px; margin-top: var(--s-s); }
.daybar-tick {
  position: absolute; top: 0;
  transform: translateX(-50%);
  font-family: var(--f-mono);
  font-size: .68rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.daybar-tick::before {
  content: ""; position: absolute; left: 50%; top: -6px;
  width: 1px; height: 5px; background: var(--rule);
}

/* Os arranques do agente: colchetes POR BAIXO do dia, não a moldura dele
   (D2 -- o dia é a unidade, a sessão é o detalhe). */
.daybar-runs { position: relative; height: var(--s-4xl); margin-top: var(--s-xs); overflow: hidden; }
.daybar-run {
  position: absolute; top: 0; height: 34px;
  display: flex; align-items: flex-end; justify-content: center;
  padding-bottom: var(--s-xs);
  border: 1.5px solid var(--rule);
  border-top: 0;
  border-radius: 0 0 var(--r-s) var(--r-s);
  font-family: var(--f-mono);
  font-size: .68rem;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
}

/* O arranque que ainda não terminou: o colchete perde a perna da direita, e
   é só isso. A forma diz "isto continua para lá do fim do desenho" sem
   precisar de cor, de animação ou de uma palavra -- um colchete fechado é
   uma afirmação sobre quando é que aquilo acabou, e às 16:40 de um dia a
   decorrer essa afirmação seria falsa.

   O nome segue `.turno-status.is-live` e `.sidebar-person.is-live`, que já
   existem neste ficheiro para o mesmo facto. */
.daybar-run.is-live { border-right: 0; border-bottom-right-radius: 0; }

/* O buraco entre dois arranques -- a resposta literal a "porque é que são
   duas sessões?". Estava desenhado como "nada aconteceu", igual às horas
   antes de a pessoa chegar; é a resposta à pergunta que motivou o
   redesenho inteiro. */
.daybar-gap {
  position: absolute; top: 0; height: 34px;
  display: grid; place-items: center;
  border-bottom: 1.5px dashed var(--clay);
  font-family: var(--f-mono);
  font-size: .66rem;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
}
/* Buraco EXPLICADO pelos dados (mudou de projecto) -- a causa está
   resolvida, não há excepção nenhuma a assinalar. */
.daybar-gap.is-known { border-bottom-color: var(--accent); border-bottom-style: solid; }

/* .daybar-read existiu aqui: um <p id="daybar-read"> vazio, reservado para
   uma leitura do bloco sob o rato que nenhum JavaScript alguma vez escreveu
   -- ocupava espaço em permanência sem nunca mostrar nada. Removido com o
   elemento em _dia_daybar.html na revisão adversarial de 2026-08-12 (item
   5): guarda-se a informação (title/aria-label em cada bloco), tira-se a
   promessa de uma leitura que não existe. */

.daybar-legend {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-xl);
  margin-top: var(--s-xl);
  font-size: .76rem;
  color: var(--ink-2);
}
.daybar-legend span { display: inline-flex; align-items: center; gap: var(--s-s); }
.daybar-legend .ramp b { display: flex; box-shadow: inset 0 0 0 1px var(--ink-2); border-radius: 3px; }
.daybar-legend .ramp b .ramp-chip { width: 15px; height: 11px; border-radius: 0; box-shadow: none; }

/* A amostra da pausa reproduz a FORMA, não a cor: um filete, não um
   quadrado. Sem isto, pausa (1,44:1), sem prova (1,25:1) e descartado
   (1,25:1) eram três quadrados brancos com uma palavra ao lado. */
.daybar-legend .sw { flex: none; width: 13px; height: 13px; border-radius: 3px; display: grid; align-content: center; }
.daybar-legend .sw.is-pause::before { content: ""; display: block; height: 3px; background: var(--ink-2); }
/* Mesma forma que .daybar-block.is-without-evidence agora usa: moldura sem
   preenchimento, não um quadrado cheio -- a amostra da legenda tem de
   sobreviver a preto e branco pela mesma razão que o próprio bloco. */
.daybar-legend .sw.is-without-evidence { background: transparent; box-shadow: inset 0 0 0 1.5px var(--clay); }
.daybar-legend .sw.is-discard {
  background-color: var(--clay-pale);
  background-image: repeating-linear-gradient(-45deg, var(--clay) 0 2px, transparent 2px 5px);
  box-shadow: inset 0 0 0 1.5px var(--clay);
}

.daybar-conta {
  margin-top: var(--s-xl);
  padding-top: var(--s-l);
  border-top: 1px solid var(--rule);
  font-size: .86rem;
  color: var(--ink-2);
}
.daybar-conta b { color: var(--ink); font-family: var(--f-mono); font-weight: 500; }

@media (max-width: 860px) { .daybar-runs { height: 52px; } }
@media (max-width: 680px) { .daybar { padding: var(--s-xl) var(--s-l) var(--s-l); } }


/* ----------------------------------------------------------------------------
   .por-projecto -- o dia quebrado por projecto
   -------------------------------------------------------------------------- */

/* UMA grelha para todas as linhas, e é isso que faz as barras significarem
   alguma coisa.

   A versão anterior punha as linhas lado a lado num flex e dava a cada uma a
   sua própria grelha `auto minmax(60px,1fr) auto`. As colunas `auto` -- nome
   do projecto e duração -- têm larguras diferentes em cada linha, portanto o
   `1fr` sobrava quantidades diferentes: um carril de 393px numa linha e de
   71px noutra. As percentagens eram calculadas contra **réguas diferentes**,
   e 4h13 contra 2h00 (rácio real 2,1×) desenhava-se a 11,8×. Medido no ecrã
   na revisão adversarial de 2026-08-12.

   Uma barra que exagera é pior do que barra nenhuma: a barra nenhuma não
   afirma nada, e esta afirmava que um projecto levou doze vezes mais tempo
   do que o outro.

   `display: contents` nas linhas faz os três filhos de cada `.pp` entrarem
   directamente nesta grelha, e é isso que põe todos os carris na mesma
   coluna. O nome mais comprido define a primeira coluna para toda a gente --
   que é exactamente o que se quer quando o objectivo é comparar. */
.por-projecto {
  display: grid;
  grid-template-columns: auto minmax(60px, 1fr) auto;
  align-items: center;
  column-gap: var(--s-m);
  row-gap: var(--s-m);
  margin-top: var(--s-xl);
  padding-top: var(--s-xl);
  border-top: 1px solid var(--rule);
}
.por-projecto .k {
  grid-column: 1 / -1;
  font-family: var(--f-mono); font-size: .68rem;
  /* `.k` passou de <span> a <h3> (Tarefa A, sessão 018): como filho directo
     de `.por-projecto` (display:grid) o "outer display" já era blockificado
     antes disto, por isso a caixa não muda -- mas o negrito por omissão do
     agente de utilizador para <h3> é novo, e nenhum <span> desta classe
     alguma vez o teve. */
  font-weight: 400;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2);
}
.por-projecto .pp { display: contents; }
.por-projecto .pp b { font-weight: 600; font-size: .88rem; white-space: nowrap; }
.por-projecto .pp .tr { height: 8px; border-radius: 4px; background: var(--rule); overflow: hidden; }
.por-projecto .pp .tr i { display: block; height: 100%; background: var(--accent); }
.por-projecto .pp em {
  font-style: normal;
  font-family: var(--f-mono); font-size: .84rem; font-variant-numeric: tabular-nums;
}
/* --accent sólido sobre --rule mede 4,67:1. Não há razão para gastar
   contraste numa barra que codifica dados. */


/* ----------------------------------------------------------------------------
   .sem-prova -- a marca do tempo sem prova, onde há um total
   ----------------------------------------------------------------------------
   D9, estendida: se um ecrã mostra um total, mostra também o tempo sem
   prova ao lado, sempre fora dele.
   -------------------------------------------------------------------------- */

/* A marca da excepção é a FORMA; o texto fica em --ink-2, que passa AA. Um
   texto de 13px em --clay mede 3,94:1 e falha; em --clay-ink mede 6,37:1 e
   passa -- mas aqui a excepção já está dita pela moldura, e pintar também o
   texto faria a linha gritar mais do que o número que ela qualifica. */
.sem-prova {
  display: inline-flex;
  align-items: center;
  font-size: .84rem;
  color: var(--ink-2);                        /* 5,95:1 sobre --surface */
}
.sem-prova::before {
  content: "";
  flex: none;
  width: 10px; height: 10px;
  margin-right: 7px;
  border-radius: 2px;
  background: var(--clay-pale);
  box-shadow: inset 0 0 0 1.5px var(--clay);  /* 3,94:1 sobre --surface */
}


/* ----------------------------------------------------------------------------
   .manual-mark -- a marca do tempo manual, já DENTRO do total
   ----------------------------------------------------------------------------
   Ao contrário de .sem-prova (sempre fora do total que qualifica), o tempo
   manual JÁ conta -- o dono/gestor que o criou já garante por ele (ver
   apps.tracking.manual_entries). Este marcador só identifica a origem, nunca
   soma outra vez, por isso nunca --clay (a cor de "excepção que pede acção"):
   a mesma família visual tracejada do crachá "Manual" de session_list.html/
   session_detail.html, --ink-2, um facto a assinalar, não uma acusação.
   -------------------------------------------------------------------------- */

.manual-mark {
  display: inline-flex;
  align-items: center;
  font-size: .84rem;
  color: var(--ink-2);                        /* 5,95:1 sobre --surface */
}
.manual-mark::before {
  content: "";
  flex: none;
  width: 10px; height: 10px;
  margin-right: 7px;
  border-radius: 2px;
  border: 1.5px dashed var(--ink-2);
}
.manual-mark.is-tiny { font-size: .7rem; margin-top: 5px; }
.manual-mark.is-tiny::before { width: 8px; height: 8px; margin-right: 5px; }


/* ----------------------------------------------------------------------------
   .week-table -- Folha de horas
   ----------------------------------------------------------------------------
   Pessoas em linha, dias em coluna. Cada célula abre esse dia -- incluindo
   as vazias, que é o que o gestor procura.
   -------------------------------------------------------------------------- */

.week-table { width: 100%; min-width: 820px; border-collapse: separate; border-spacing: 0; }
.week-table th, .week-table td { border-bottom: 1px solid var(--rule); }

.week-table thead th {
  padding: var(--s-m) var(--s-m);
  font-family: var(--f-mono); font-size: .7rem; font-weight: 500;
  letter-spacing: .06em; text-transform: uppercase;
  text-align: center; color: var(--ink-2);
}
.week-table thead th.col-name { text-align: left; }
.week-table thead th b {
  display: block;
  font-family: var(--f-display); font-size: .96rem;
  letter-spacing: 0; text-transform: none; color: var(--ink);
}
.week-table thead th.is-today b { color: var(--accent); }   /* 6,74:1 sobre --surface */

/* tbody th.col-name -- item 9 da revisão adversarial de 2026-08-12: o nome
   da pessoa era <td>, sem semântica de cabeçalho de linha; passou a
   <th scope="row">, e um <th> vem do navegador centrado e a negrito por
   omissão, daí o text-align e o font-weight aqui repetidos em vez de
   deixados implícitos como estavam quando isto era um <td> comum. */
.week-table td.col-name, .week-table tbody th.col-name {
  padding: var(--s-m) var(--s-l) var(--s-m) 0;
  font-weight: 600; font-size: .94rem; white-space: nowrap;
  text-align: left;
}
.week-table td.col-name small, .week-table tbody th.col-name small { display: block; font-weight: 400; font-size: .78rem; color: var(--ink-2); }

.week-cell { padding: var(--s-s) var(--s-xs); text-align: center; }
.week-cell a {
  display: block;
  padding: 9px var(--s-xs) var(--s-m);
  border: 1.5px solid transparent;
  border-radius: var(--r-s);
  text-decoration: none;
  color: inherit;
}
/* O fundo da célula já é --surface, portanto pintar --surface no hover era
   metade de uma regra nula, e sobrava um bordo a 1,34:1: a interacção
   principal do ecrã não se via. */
.week-cell a:hover { border-color: var(--accent); background: var(--accent-pale); }

.week-cell .h { display: block; font-family: var(--f-mono); font-weight: 500; font-size: .98rem; font-variant-numeric: tabular-nums; }
.week-cell .none { color: var(--ink-2); font-family: var(--f-mono); }
.week-cell .mini { margin-top: var(--s-s); }

.week-cell.is-weekend { background: rgba(216, 207, 195, .28); }
/* Um dia que ainda não aconteceu não é um dia em que não se trabalhou: com
   cinco das sete colunas a mostrar o mesmo travessão, o ecrã inteiro
   parecia avariado. */
.week-cell.is-future { opacity: .4; }

.week-table td.col-total, .week-table th.col-total {
  padding-right: 0;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-weight: 500; text-align: right;
}
/* Acima do limite semanal da empresa (D7): argila, porque é uma excepção
   que pede acção de quem lê -- nunca uma acusação a quem trabalhou.
   --clay-ink, não --clay: a .98rem, --clay mede 3,94:1 e falha AA. */
.week-table td.col-total.is-over { color: var(--clay-ink); }   /* 6,37:1 */
.week-table td.col-total small { display: block; font-family: var(--f-body); font-size: .7rem; font-weight: 400; }

.week-table tfoot td {
  border-bottom: 0;
  border-top: 2px solid var(--ink);
  padding-top: var(--s-l);
  text-align: center;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums; font-weight: 500;
}
.week-table tfoot td.col-name { text-align: left; font-family: var(--f-body); }
.week-table tfoot td small { display: flex; justify-content: center; margin-top: var(--s-xs); }

/* A banda de temperatura em miniatura -- o mesmo componente, não um
   segundo. */
.temp-band.is-mini { height: 5px; border-radius: 3px; }
.sem-prova.is-tiny { font-size: .7rem; margin-top: 5px; }
.sem-prova.is-tiny::before { width: 8px; height: 8px; margin-right: 5px; }


/* ----------------------------------------------------------------------------
   .team-table -- a lista da equipa (vista Lista do Painel)
   ----------------------------------------------------------------------------
   O Live Dashboard do Monitask, em Turno: uma linha por pessoa, com
   Hoje · Ontem · 7 dias até hoje lado a lado.
   -------------------------------------------------------------------------- */

.team-table { width: 100%; min-width: 760px; border-collapse: collapse; }
.team-table thead th {
  padding: 0 var(--s-l) var(--s-m) 0;
  border-bottom: 1px solid var(--rule);
  text-align: left;
  font-family: var(--f-mono); font-size: .7rem; font-weight: 500;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2);
}
.team-table thead th.num-cell { text-align: right; }
.team-table thead th.is-now { color: var(--accent); }
.team-table td { padding: var(--s-l) var(--s-l) var(--s-l) 0; border-bottom: 1px solid var(--rule); vertical-align: middle; }
.team-table tr:last-child td { border-bottom: 0; }
.team-table tbody tr:hover td { background: var(--surface); }

.team-person { display: flex; align-items: center; gap: var(--s-l); }
.team-person b { display: block; font-family: var(--f-display); font-size: 1rem; }
.team-person b a { text-decoration: none; }
.team-person b a:hover { text-decoration: underline; }
.team-person small { display: block; font-size: .78rem; color: var(--ink-2); }

/* .person-avatar, não .avatar -- palavra genérica solta que o cabeçalho
   deste ficheiro já avisa contra. */
.person-avatar {
  flex: none; position: relative;
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-pale);
  color: var(--accent-2);                     /* 7,62:1 sobre --accent-pale */
  font-family: var(--f-display); font-weight: 700; font-size: .84rem;
}
.person-avatar.is-live::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--bg);
}

/* .cellh/.cella -- reposto na revisão adversarial da Tarefa A/B (sessão 018).
   Critério único para todo este ficheiro, decidido nessa revisão: CSS que um
   spec ACTIVO descreve fica, mesmo sem consumidor hoje -- nunca se decide
   caso a caso se "parece" renomeado ou abandonado. `.cellh`/`.cella` estão
   listados lado a lado com `.team-table`/`.team-person`/`.person-avatar`
   como componentes da mesma fase em docs/superpowers/specs/
   2026-08-12-dia-interface.md:2366-2368; sem um critério único, ficaríamos
   com metade desse inventário apagada e a outra metade viva, o pior dos dois
   estados para quem vier construir o que falta. Só sai deste ficheiro CSS
   que não conste de spec nenhum (foi o caso de `.app-nav-count`, removido
   nesta mesma revisão). */
.cellh { display: block; text-align: right; font-family: var(--f-mono); font-weight: 500; font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.cellh.is-zero { color: var(--ink-2); font-weight: 400; }
.cella { display: block; margin-top: var(--s-2xs); text-align: right; font-family: var(--f-mono); font-size: .74rem; color: var(--ink-2); }
/* O tempo sem prova nunca soma ao número da esquerda, mas nunca desaparece
   do sítio onde o número aparece (D9). --clay-ink, nunca --clay (3,94:1 a
   11,8px). */
.cella.is-gap { color: var(--clay-ink); }     /* 6,37:1 sobre --surface */

.shot-card.is-thumb { width: 92px; }


/* ----------------------------------------------------------------------------
   .hour-strip / .hour-band / .hour-shots -- a grelha de capturas
   ----------------------------------------------------------------------------
   O alinhamento é o requisito, não o acabamento: banda e miniaturas
   partilham o mesmo grid-template-columns e a mesma column-gap dentro do
   mesmo contentor de largura fixa, para que o alinhamento seja estrutural
   em vez de aritmético. Reutiliza `.shot-card` (§2.6 -- `.shot-grid` já
   existe no detalhe de sessão como `flex; width:max-content`, por isso a
   grelha nova chama-se `.hour-shots` e não colide).
   -------------------------------------------------------------------------- */

.hour-strip { margin-bottom: var(--s-3xl); }

.hour-head { display: flex; align-items: center; gap: var(--s-l); margin-bottom: var(--s-m); }
.hour-head h3 { font-family: var(--f-mono); font-size: .92rem; font-weight: 500; letter-spacing: .04em; }
.hour-head .rule { flex: 1; height: 1px; background: var(--rule); }
.hour-count { font-family: var(--f-mono); font-size: .7rem; color: var(--ink-2); }

/* Rola dentro da própria caixa, nunca a página -- a mesma regra de
   .table-scroll e .shot-strip. É isto que deixa a geometria FIXA em seis
   colunas a qualquer largura, e é a geometria fixa que garante o
   alinhamento. */
.hour-scroll { overflow-x: auto; padding-bottom: var(--s-s); }
.hour-cols { min-width: 640px; }

/* As duas grelhas partilham template e goteira. Não há aritmética a fazer:
   a célula k da banda e a coluna k da grelha ocupam o mesmo intervalo, por
   construção. */
.hour-band,
.hour-shots {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  column-gap: var(--s-l);
}
.hour-band { height: 22px; margin-bottom: var(--s-m); }
.hour-shots { row-gap: var(--s-l); }

.hour-band-cell { display: flex; gap: 0; border-radius: var(--r-s); overflow: hidden; }
.hour-band-cell .seg {
  display: flex; align-items: center;
  min-width: 0; padding-inline: var(--s-m);
  background: var(--accent-pale);
  color: var(--accent-2);                     /* 7,62:1 sobre --accent-pale */
  font-style: normal; font-size: .76rem;
  white-space: nowrap; overflow: hidden;
}
/* A pausa na banda mantém a mesma linguagem da linha do dia: um filete,
   não um bloco cheio. --ink sobre --rule mede 10,79:1; --ink-2 mede
   4,12:1 e falhava AA para .76rem. */
.hour-band-cell .seg.is-pause {
  background: var(--rule);
  color: var(--ink);
  box-shadow: inset 0 -50% 0 -1.5px var(--ink-2);
}
.hour-band-cell .seg.is-gap {
  background: var(--clay-pale);
  color: var(--clay-ink);                     /* 5,08:1 sobre --clay-pale */
  box-shadow: inset 0 0 0 1.5px var(--clay);  /* 3,14:1 sobre --clay-pale */
}
.hour-band-cell .seg.is-off { background: transparent; }

/* Posição explícita, sempre segura: a grelha nunca muda de contagem de
   colunas, portanto não há risco de criar colunas implícitas. */
.hour-shots > * { grid-column: var(--slot) / var(--slot-end, span 1); }

.shot-card { position: relative; }            /* para .shot-count e .ramp-chip */

.shot-count {
  position: absolute; right: var(--s-s); bottom: 38px;
  min-width: 22px; height: 22px; padding-inline: 5px;
  display: grid; place-items: center;
  border-radius: 5px;
  background: rgba(36, 29, 23, .72);
  color: var(--bg);                           /* 12,77:1 sobre o véu */
  font-family: var(--f-mono); font-size: .72rem; font-variant-numeric: tabular-nums;
}

/* O layout de linha (hora à esquerda, actividade à direita) que a legenda de
   captura por hora precisa -- restrito a `.hour-shots`, e é essa restrição
   que é a correcção.

   A primeira versão desta regra dizia `.shot-caption { display: flex }` solta,
   com um comentário a explicar que era "aditiva" porque não substituía
   nenhuma propriedade da regra original (:1255). Era verdade propriedade a
   propriedade e falso em efeito: `display:flex` transforma cada nó de texto
   solto em item de flex, e a legenda do detalhe de sessão -- que é texto
   corrido com travessões -- partiu-se em "Ecrã" / "—" / "1920×1080" / "—" /
   "09:03:00", espalhados de bordo a bordo. Apanhado na revisão adversarial
   de 2026-08-12, no ecrã, em /app/sessions/<pk>/.

   A lição, escrita porque se vai repetir: um selector de classe solto num
   ficheiro partilhado por dois ecrãs não é aditivo por não substituir
   propriedades. É aditivo quando não alcança o outro ecrã. */
.hour-shots .shot-caption {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-m);
}
.shot-time { font-family: var(--f-mono); font-size: .78rem; font-variant-numeric: tabular-nums; color: var(--ink); }
.shot-act { display: inline-flex; align-items: center; gap: var(--s-s); font-family: var(--f-mono); font-size: .7rem; color: var(--ink-2); }

/* Uma corrida sem prova é UM aviso que atravessa as fatias que ocupou --
   nunca seis caixas iguais a repetir a mesma frase. */
.shot-card.is-gap {
  display: grid; place-items: center;
  padding: var(--s-xl) var(--s-l);
  text-align: center;
  border-style: dashed;
  border-color: var(--clay);                  /* 3,94:1 sobre --surface */
  background: var(--clay-pale);
}
.shot-card.is-gap p { font-size: .82rem; color: var(--clay-ink); }   /* 5,08:1 sobre --clay-pale */
.shot-card.is-gap p b { display: block; margin-bottom: 3px; font-family: var(--f-mono); font-size: .78rem; font-weight: 500; }

.shot-card.is-discard {
  background-color: var(--clay-pale);
  background-image: repeating-linear-gradient(-45deg, var(--clay) 0 2px, transparent 2px 5px);
}

/* A miniatura é uma ligação (templates/dashboard/_dia_horas.html) e tem de
   o parecer antes do clique -- caso contrário fica exactamente o problema
   que esta tarefa veio resolver, só que a um passo de distância: uma prova
   que abre e ninguém descobre que abre. */
.shot-open { display: block; position: relative; border-radius: var(--r-s); }
.shot-open:hover img { opacity: .88; }
.shot-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


/* ----------------------------------------------------------------------------
   .shot-viewer -- a captura inteira, por cima da página
   ----------------------------------------------------------------------------
   Um `<dialog>` nativo: o foco preso lá dentro, o Esc a fechar, o resto da
   página inerte e o `::backdrop` são todos do browser. Ver o comentário no
   topo de templates/dashboard/_dia_capturas.html.

   O véu é `--ink` e não preto. A casa é quente e de papel; um preto puro
   por baixo de uma captura de um ecrã de trabalho lê-se como sala de
   controlo, que é o oposto da tese deste sistema (ver o topo do ficheiro).
   O par véu/texto é o mesmo que `.shot-count` já usa por cima das
   miniaturas -- 12,77:1.
   -------------------------------------------------------------------------- */

.shot-viewer {
  /* O `<dialog>` traz `max-width: calc(100% - 6px)`, `max-height` e margem
     automática do UA. Sem os anular, a captura abre dentro de uma caixa
     centrada com bordas de papel à volta, em vez de ocupar o ecrã. */
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: rgba(36, 29, 23, .96);
  color: var(--bg);
  overflow: hidden;
}
.shot-viewer::backdrop { background: rgba(36, 29, 23, .96); }

/* O palco ocupa tudo menos a barra; é ele que rola quando a captura está
   ampliada, nunca a página por baixo. */
.shot-viewer-stage {
  position: absolute;
  inset: 0 0 var(--viewer-bar, 64px);
  display: grid;
  place-items: center;
  padding: var(--s-2xl);
  overflow: auto;
}

/* Por omissão a captura cabe inteira -- é assim que se vê o ecrã de que ela
   é prova. `is-zoomed` passa-a a tamanho real e deixa o palco rolar, que é
   o que serve para ler texto pequeno dentro dela. */
.shot-viewer-img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--r-s);
  background: rgba(36, 29, 23, .5);
}
.shot-viewer.is-zoomed .shot-viewer-stage { place-items: start; }
.shot-viewer.is-zoomed .shot-viewer-img {
  max-width: none;
  max-height: none;
  border-radius: 0;
}

.shot-viewer-state {
  grid-area: 1 / 1;
  font-size: .88rem;
  color: var(--rule);
  text-align: center;
}

.shot-viewer-close,
.shot-viewer-nav,
.shot-viewer-zoom {
  cursor: pointer;
}

.shot-viewer-close {
  position: absolute;
  top: var(--s-xl);
  right: var(--s-xl);
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(237, 231, 223, .12);
  color: var(--bg);
  font-size: 1.5rem;
  line-height: 1;
}
.shot-viewer-close:hover { background: rgba(237, 231, 223, .22); }

/* Centradas na vertical do palco, não da janela: com a barra em baixo, o
   centro da janela cai por cima dela nos ecrãs baixos. */
.shot-viewer-nav {
  position: absolute;
  top: calc(50% - var(--viewer-bar, 64px) / 2);
  transform: translateY(-50%);
  width: 52px;
  height: 76px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--r-s);
  background: rgba(237, 231, 223, .10);
  color: var(--bg);
  font-size: 2.2rem;
  line-height: 1;
}
.shot-viewer-nav:hover:not(:disabled) { background: rgba(237, 231, 223, .20); }
/* Desactivado, não escondido: um botão que some desloca o outro debaixo do
   ponteiro de quem carrega várias vezes seguidas para avançar. */
.shot-viewer-nav:disabled { opacity: .28; cursor: default; }
.shot-viewer-nav.is-prev { left: var(--s-m); }
.shot-viewer-nav.is-next { right: var(--s-m); }

.shot-viewer-close:focus-visible,
.shot-viewer-nav:focus-visible,
.shot-viewer-zoom:focus-visible { outline: 2px solid var(--bg); outline-offset: 2px; }

.shot-viewer-bar {
  position: absolute;
  inset: auto 0 0 0;
  min-height: var(--viewer-bar, 64px);
  display: flex;
  align-items: center;
  gap: var(--s-xl);
  padding: var(--s-m) var(--s-xl);
  background: rgba(36, 29, 23, .82);
  border-top: 1px solid rgba(237, 231, 223, .14);
}
.shot-viewer-id { flex: 1; min-width: 0; font-size: .84rem; }
.shot-viewer-project { display: block; font-weight: 500; }
.shot-viewer-when {
  font-family: var(--f-mono);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  color: var(--rule);
}
.shot-viewer-pos {
  flex: 1;
  text-align: right;
  font-family: var(--f-mono);
  font-size: .76rem;
  font-variant-numeric: tabular-nums;
  color: var(--rule);
}
.shot-viewer-sep { margin-inline: var(--s-s); }

/* O botão da barra vive sobre o véu escuro: o `.btn-quiet` de papel
   desaparecia lá dentro. Mesma correcção que `.notice .btn-quiet` já faz
   para o seu próprio fundo. */
.shot-viewer .btn-quiet {
  border-color: rgba(237, 231, 223, .32);
  color: var(--bg);
}
.shot-viewer .btn-quiet:hover {
  border-color: var(--bg);
  background: rgba(237, 231, 223, .12);
  color: var(--bg);
}

/* Num ecrã estreito a barra empilha-se e as setas encostam-se às bordas --
   e a barra passa a ter altura própria, por isso `--viewer-bar` sobe com
   ela: é a mesma variável que posiciona o palco e as setas, e um número
   escrito duas vezes seria um desalinhamento à espera de acontecer. */
@media (max-width: 680px) {
  .shot-viewer { --viewer-bar: 96px; }
  .shot-viewer-bar { flex-wrap: wrap; gap: var(--s-m); }
  .shot-viewer-id { flex-basis: 100%; }
  .shot-viewer-pos { text-align: left; }
  .shot-viewer-nav { width: 40px; height: 60px; font-size: 1.8rem; }
  .shot-viewer-stage { padding: var(--s-m); }
}


/* ----------------------------------------------------------------------------
   .usage-list -- aplicações, por contagem de blocos
   -------------------------------------------------------------------------- */

.usage-list { display: flex; flex-direction: column; gap: var(--s-m); }
.usage-row {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr) auto;
  align-items: center; gap: var(--s-l);
  font-size: .88rem;
}
.usage-row .track { height: 8px; border-radius: 4px; background: var(--rule); overflow: hidden; }
/* display:block -- o .track é blockificado por ser item de grelha, mas o
   .fill lá dentro continua inline e ignora width/height: as barras mediam
   0×0 e o painel mostrava carris vazios. */
.usage-row .fill { display: block; height: 100%; background: var(--accent); }
.usage-row .t { font-family: var(--f-mono); font-size: .82rem; font-variant-numeric: tabular-nums; color: var(--ink-2); }

@media (max-width: 680px) {
  .usage-row { grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-s) var(--s-m); }
  .usage-row .track { grid-column: 1 / -1; }
}


/* ----------------------------------------------------------------------------
   Peças pequenas -- §3.12 da spec de interface
   -------------------------------------------------------------------------- */

/* .view-switch -- Cartões ⇄ Lista. Dívida registada na própria spec: é,
   forma por forma, o .lang-switch do site público (mais acima neste
   ficheiro). Fundem-se num só componente quando qualquer um for tocado por
   outra razão -- não agora, porque renomear .lang-switch obriga a mexer em
   cinco templates públicos que esta tarefa não toca. */
.view-switch { display: flex; gap: 3px; padding: 3px; background: var(--rule); border-radius: 999px; }
.view-switch a {
  padding: var(--s-s) 15px; border-radius: 999px;
  font-size: .82rem; text-decoration: none; color: var(--ink-2);
}
.view-switch a[aria-current="page"] {
  background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: var(--shadow-soft);
}

.breadcrumb { display: flex; align-items: center; gap: var(--s-m); margin-bottom: var(--s-m); font-size: .84rem; color: var(--ink-2); }
.breadcrumb a { color: var(--accent); }       /* 6,74:1 sobre --surface */

/* .turno-card.is-link -- o cartão passa a levar ao dia daquela pessoa.
   flex-direction:column, não display:block: um cartão com .turno-runs
   estica os vizinhos na grelha e, sem align-items:stretch, o conteúdo
   centra-se verticalmente. */
.turno-card.is-link {
  display: flex; flex-direction: column; align-items: stretch;
  text-decoration: none; color: inherit;
  transition: transform .16s ease, box-shadow .16s ease;
}
.turno-card.is-link:hover {
  transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(36,29,23,.06), 0 20px 38px -10px rgba(36,29,23,.22);
}

/* Rodapé com o número de arranques -- o facto que hoje só se descobre indo
   à lista de sessões e contando linhas. */
.turno-runs {
  display: flex; align-items: center; gap: 7px;
  margin-top: var(--s-l); padding-top: var(--s-l);
  border-top: 1px dashed var(--rule);
  font-size: .78rem; color: var(--ink-2);
}
.turno-runs .pips { display: flex; gap: 3px; }
.turno-runs .pip { width: 7px; height: 7px; border-radius: 2px; background: var(--accent); }   /* 6,74:1, sólido -- não .55 de opacidade (2,48:1) */

/* .notice.is-row -- só os avisos que têm botão viram linha: pôr flex no
   .notice inteiro faz de cada <strong> no meio de uma frase um item de
   flex, e a frase parte-se com metade encostada à direita. */
.notice.is-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s-xl); flex-wrap: wrap; }
.notice .btn-quiet { border-color: rgba(36, 29, 23, .28); color: var(--ink); }
.notice .btn-quiet:hover { border-color: var(--ink); background: var(--surface); }

/* .data-table.is-wide -- modificador, não alteração: o .data-table sem
   min-width encolhe em vez de rolar, e o .table-scroll fica inerte. */
.data-table.is-wide { min-width: 640px; }


/* ----------------------------------------------------------------------------
   .skip e .sr-only -- acessibilidade
   -------------------------------------------------------------------------- */

/* Salta a barra lateral inteira -- que são 7 ligações mais N colaboradores
   antes de qualquer conteúdo, em todas as páginas. z-index:100 porque o
   grão de papel (body::before) está em 60 e a .date-bar em 40. */
.skip {
  position: absolute; left: var(--s-m); top: -60px; z-index: 100;
  padding: var(--s-m) var(--s-xl);
  background: var(--ink); color: var(--bg);   /* 13,54:1 */
  border-radius: var(--r-s);
  text-decoration: none;
  transition: top .12s ease;
}
.skip:focus { top: var(--s-m); }

.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;
}


/* ----------------------------------------------------------------------------
   Grelha responsiva -- quatro métricas sem célula órfã (§4 da spec)
   ----------------------------------------------------------------------------
   São sempre quatro métricas. Com auto-fit, três colunas deixam a quarta
   sozinha e sobra meia célula da cor do rule no meio dos números -- com o
   filete de argila do needs-action a parecer que sublinha a linha de cima.
   Modificador, para não mexer no .metric-grid que Relatórios e detalhe de
   sessão já usam com outra contagem.
   -------------------------------------------------------------------------- */

.metric-grid.is-four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 680px) { .metric-grid.is-four { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 400px) { .metric-grid.is-four { grid-template-columns: 1fr; } }
