/* ============================================================
   Notificações — Lekto
   ============================================================
   Três superfícies, uma fonte. A regra que decide qual usar:

     evento aconteceu        → sino (acumula, pode esperar)
     evento acabou de chegar → toast (10 s ao lado do sino)
     estado persiste         → banner (fica até resolver)
     ação foi minha          → nada aqui; é o .toast de sistema do styles.css

   O toast de notificação e o `.toast` de sistema são componentes DIFERENTES e
   de propósito diferente: aquele confirma o que EU fiz, este avisa do que
   ACONTECEU. Misturar os dois foi o erro que este arquivo evita — por isso o
   prefixo próprio `nt-`, sem tocar em `.toast`.

   Base de DS: DS:Alert (variantes Negative · Warning · Success · Neutral,
   anatomia ícone + title + description + action + fechar). O painel reaproveita
   a linguagem do log (dot 34 px + ícone no traço do DS), porque notificação e
   log são o MESMO evento em superfícies diferentes.

   ESCOPO: Lekto — o outro produto não tem este módulo, ver o guarda abaixo.
   ============================================================ */


/* ============================================================
   1 · Sino — contador de não lidas
   ============================================================ */
.nt-bell { position: relative; }

.nt-bell__badge {
  position: absolute; top: 4px; right: 4px;
  min-width: 17px; height: 17px; padding: 0 4px;
  display: grid; place-items: center;
  border-radius: var(--lkt-radius-pill);
  background: var(--lkt-destructive-pure); color: var(--color-ivory);
  font-family: var(--theme-font-family-base); font-size: 10px; font-weight: 800; line-height: 1;
  border: 2px solid var(--color-ivory);
  pointer-events: none;
}
.nt-bell__badge[hidden] { display: none; }

/* O sino "toca" quando chega notificação nova — sinal periférico, sem som e
   sem roubar foco. Só o ícone se move; o badge fica parado para continuar
   legível durante a animação. */
.nt-bell.is-ringing svg { animation: nt-ring 620ms var(--ease); transform-origin: 50% 22%; }
@keyframes nt-ring {
  0%, 100% { rotate: 0deg; }
  15% { rotate: -13deg; }
  32% { rotate: 10deg; }
  50% { rotate: -6deg; }
  68% { rotate: 4deg; }
  85% { rotate: -2deg; }
}

/* ============================================================
   2 · Painel — a caixa de entrada
   ============================================================
   Ancorado ao sino por JS (getBoundingClientRect), porque o sino muda de lugar:
   rail do professor, rail do admin (que ainda colapsa) e barra superior no
   mobile. Posição fixa em CSS quebraria em pelo menos um desses três.
   ============================================================ */
.nt-panel {
  /* Largura útil em variável: o modo "extensão do rail" precisa somar a ela o
     pedaço que fica escondido atrás da barra, e a vista de preferências troca
     só este número. */
  --nt-w: min(392px, calc(100vw - 32px));
  position: fixed; z-index: 180;
  width: var(--nt-w);
  display: flex; flex-direction: column;
  /* DS:Modal — nada fixo: o painel inteiro é a área de rolagem, com
     cabeçalho e rodapé no fluxo. O teto de altura é o da janela. */
  max-height: calc(100vh - 120px);
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--color-ivory);
  /* Mesmo token de borda do rail (styles.css/admin.css), não o primitivo
     --base-200: no tema lekto os dois valem o mesmo, mas o aura repinta só o
     token de tema — e a emenda barra|painel, que o modo rail quer que se leia
     como superfície única, trocava de matiz no meio da linha. */
  border: 1px solid var(--theme-panel-border);
  border-radius: var(--border-radius-md);
  box-shadow: var(--theme-modal-shadow);
}
.nt-panel[hidden] { display: none; }

.nt-panel__head {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 16px 12px;
  border-bottom: 1px solid var(--base-100);
}
.nt-panel__title {
  flex: 1; min-width: 0;
  font-family: var(--theme-font-family-heading); font-size: 17px; font-weight: 800;
  letter-spacing: -.01em; color: var(--base-800);
}

/* Filtro Todas / Não lidas — mesmo segmentado do resto do app. */
.nt-seg { display: flex; gap: 2px; padding: 3px; background: var(--lkt-surface-pale); border-radius: var(--lkt-radius-pill); }
.nt-seg__opt {
  padding: 5px 12px; border-radius: var(--lkt-radius-pill);
  font-family: var(--theme-font-family-base); font-size: 12.5px; font-weight: 700; color: var(--base-600);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.nt-seg__opt:hover { color: var(--base-800); }
.nt-seg__opt.is-active { background: var(--color-ivory); color: var(--lkt-primary-pure); box-shadow: var(--lkt-shadow-level1); }

.nt-panel__list { padding: 6px 0; }

.nt-panel__voltar {
  display: grid; place-items: center; width: 30px; height: 30px; margin-left: -4px;
  border-radius: var(--lkt-radius-nano); color: var(--base-700);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.nt-panel__voltar svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.nt-panel__voltar:hover { background: var(--base-100); color: var(--base-800); }

/* Ajustes — irmão do voltar: mesma caixa de 30px e mesmo hover, do outro lado
   do cabeçalho. O traço é mais fino que o do voltar (1.6 contra 1.9) porque a
   engrenagem tem oito dentes no mesmo espaço em que a seta tem três linhas:
   no mesmo peso ela vira uma mancha. */
.nt-panel__cfg {
  position: relative; flex-shrink: 0;
  display: grid; place-items: center; width: 30px; height: 30px;
  border-radius: var(--lkt-radius-nano); color: var(--base-600);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
/* O quadrado VISUAL é de 30px para casar com a altura do segmentado ao lado; a
   área de TOQUE vai a 40px por pseudo-elemento, sem alterar o desenho nem o
   layout. Dedo não acerta 30px com confiança, e este é o único controle do
   cabeçalho no mobile. Os 5px que ela avança à esquerda cabem no gap de 10px
   até o segmentado, então não roubam clique dele. */
.nt-panel__cfg::after { content: ""; position: absolute; inset: -5px; }
.nt-panel__cfg svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.nt-panel__cfg:hover { background: var(--base-100); color: var(--base-800); }
.nt-panel__rodape { font-size: 12px; color: var(--base-600); font-weight: 600; }

/* ============================================================
   2b · Preferências — mesma casca, outra vista
   ============================================================
   Duas colunas de canal e uma linha por grupo. A grade é a mesma nas três
   partes (cabeçalho, linhas) para as chaves ficarem alinhadas em coluna: sem
   isso a pessoa precisa reler o cabeçalho a cada linha para saber o que está
   ligando.
   ============================================================ */
/* A vista de preferências é mais larga que a de notificações: são três colunas
   em vez de uma lista, e na largura da lista a descrição de cada grupo quebrava
   em três linhas. O JS reancora depois de trocar de vista, senão o painel
   cresce para dentro da tela em vez de a partir do sino. */
.nt-panel.is-prefs { --nt-w: min(444px, calc(100vw - 32px)); }

/* ============================================================
   2c · Extensão do menu — o painel É a barra esticada
   ============================================================
   O painel não é um cartão flutuante ao lado do sino: é a barra de menu se
   estendendo. Três consequências, e as três são o pedido:

     · ancora na BARRA, não no ícone do sino (JS: rect do .sidebar/.adm-sidebar);
     · tem a MESMA ALTURA da barra — topo e base alinhados a ela, não ao sino;
     · sai POR DEBAIXO dela: o rail sobe de z-index enquanto o painel está
       aberto (regra no fim deste bloco), então o painel emerge de trás da
       barra em vez de passar por cima.

   O trecho `--nt-tuck` é a parte que fica escondida atrás do rail. Ele entra na
   largura E como padding-left: assim a largura ÚTIL do painel continua sendo
   `--nt-w` (o conteúdo não encolhe), e o que cresce é só o pedaço encoberto.
   Ele lê o token do RAIO do rail, não um de espaçamento: o que ele precisa
   cobrir é exatamente a curva do canto, então é a esse número que ele tem de
   continuar amarrado se um dia a escala mudar.

   Toast e banner continuam ancorados no sino — são avisos passageiros, não
   extensão do menu; só o painel ganha este modo.
   ============================================================ */
.nt-panel.nt-panel--rail {
  --nt-tuck: var(--border-radius-sm-plus);
  width: calc(var(--nt-w) + var(--nt-tuck));
  padding-left: var(--nt-tuck);
  /* A altura vem do CONTEÚDO; o JS escreve o teto inline (altura da barra) e
     fixa só a base. Era `none` com top+bottom juntos, o que esticava o painel
     para a altura do rail mesmo vazio. */
  border-left: 0;
  border-radius: 0 var(--border-radius-sm-plus) var(--border-radius-sm-plus) 0;
}
/* Sobra do tempo em que a altura era a da barra: com altura de conteúdo não há
   folga para absorver, e a regra resolve para zero. Fica porque a vista de
   preferências pode encostar no teto e voltar a ter folga — o rodapé precisa ir
   para a base nesse caso, não ficar no meio do painel
   ele lê como conteúdo truncado. `auto` continua no FLUXO (não é sticky nem
   absolute, a decisão de DS acima segue valendo): ele só absorve a folga, e
   resolve para zero assim que a lista passa a transbordar. */
.nt-panel--rail .nt-panel__foot { margin-top: auto; }

/* Sino na barra superior do mobile: mesma ideia, outra orientação. Barra
   horizontal → o painel cresce para baixo com a largura dela, encostado, sem
   vão e sem canto arredondado no topo. Aqui NÃO há sobreposição: na home a
   .mobile-bar é transparente (styles.css), e um painel branco por trás dela
   apagaria o logo e o sino, que ali são brancos. */
.nt-panel.nt-panel--barra {
  width: 100vw; max-width: 100vw; left: 0; right: 0;
  border-left: 0; border-right: 0; border-top: 0;
  border-radius: 0 0 var(--border-radius-md) var(--border-radius-md);
}

/* O "por debaixo": só enquanto o painel está aberto E só no modo rail. Duas
   travas, cada uma por um motivo:
   · Deixar o rail acima de 180 em definitivo o colocaria por cima de todo modal
     do app (.modal, .deckx, .finmod, .gz-confirm também estão em 180).
   · A classe entra pelo JS somente quando a barra é vertical. A mesma
     .adm-sidebar vira barra horizontal de rodapé em ≤768px, onde não há nada
     para emergir de trás — e ali o 181 só serviria para a barra cobrir o modal. */
body.nt-panel-aberto .sidebar,
body.nt-panel-aberto .adm-sidebar { z-index: 181; }

/* Efeito colateral do bump: o tooltip do rail é pseudo-elemento DELE, então
   subiu junto e passou a ser pintado sobre o painel — bem no gesto que abre o
   painel, já que o ponteiro fica parado sobre o sino depois do clique. Com o
   painel aberto o rail não explica mais a si mesmo: quem está lendo a lista não
   precisa do rótulo do ícone que acabou de clicar. */
body.nt-panel-aberto .sidebar .nav-item::after,
body.nt-panel-aberto .sidebar .viewswitch__opt span,
body.nt-panel-aberto .adm-sidebar .adm-item span,
body.nt-panel-aberto .adm-sidebar .viewswitch__opt span { opacity: 0; }

.nt-prefs__cab,
.nt-pref { display: grid; grid-template-columns: minmax(0, 1fr) 66px 66px; align-items: center; gap: 12px; }

/* Rótulos de coluna no fluxo (DS:Modal — nada fixo). */
.nt-prefs__cab {
  padding: 12px 16px 8px; border-bottom: 1px solid var(--base-100);
}
.nt-prefs__cab span + span {
  text-align: center; font-size: 10.5px; font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; color: var(--base-600);
}

.nt-pref { padding: 14px 16px; }
.nt-pref + .nt-pref { border-top: 1px solid var(--base-100); }
.nt-pref__txt { min-width: 0; }
.nt-pref__nome { display: block; font-family: var(--theme-font-family-base); font-size: 13.5px; font-weight: 800; color: var(--base-800); }
.nt-pref__desc { display: block; margin-top: 3px; font-size: 12.5px; line-height: 1.5; color: var(--base-700); }
.nt-pref__col { display: grid; place-items: center; }

/* Subtítulo do bloco detalhado. Sem ele os alertas individuais se misturariam
   aos grupos e a tela perderia a noção de que ali se configura outra coisa. */
.nt-prefs__sec {
  padding: 16px 16px 6px; border-top: 1px solid var(--base-100);
  font-family: var(--theme-font-family-base); font-size: 10.5px; font-weight: 800;
  letter-spacing: .05em; text-transform: uppercase; color: var(--base-600);
}
/* A primeira linha depois do subtítulo não repete a divisória. */
.nt-prefs__sec + .nt-pref { border-top: 0; }

/* Item — o dot herda a gramática do log: um kind, um ícone, uma família de cor.
   Só o dot: SEM o fio conector do log. O log é a história contínua de UMA
   atribuição — o fio faz sentido porque é sempre o mesmo assunto ao longo do
   tempo. O sino é uma caixa de entrada: cada item é um evento independente,
   muitas vezes de gente, turma ou conteúdo diferentes — o fio insinuaria que
   são elos da mesma linha, o que é falso. Separador é borda, não conector. */
.nt-item {
  position: relative; width: 100%;
  display: grid; grid-template-columns: var(--log-marker) minmax(0, 1fr) 10px; gap: var(--log-gap);
  padding: var(--log-row-pad) 16px; text-align: left;
  border-bottom: 1px solid var(--base-100);
  transition: background var(--motion-dur-fast) var(--motion-ease);
}
.nt-item:last-child { border-bottom: 0; }
.nt-item:hover { background: var(--theme-surface-muted); }

.nt-item__dot {
  position: relative; z-index: 1;
  width: var(--log-marker); height: var(--log-marker); border-radius: var(--border-radius-circle);
  display: grid; place-items: center;
  background: var(--theme-surface-muted); color: var(--theme-text-muted);
}
.nt-item__dot svg { width: var(--log-icon); height: var(--log-icon); fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

.nt-item__txt { min-width: 0; }
/* block em todos: são <span> para poder viver dentro de um <button>, mas
   precisam empilhar. Sem isto, título e corpo colam numa frase só. */
.nt-item__title { display: block; font-family: var(--theme-font-family-base); font-size: var(--log-phrase-size); font-weight: 700; line-height: 1.45; color: var(--theme-text-heading); }
.nt-item__title b { font-weight: 800; }
.nt-item__body { display: block; margin-top: 2px; font-size: 13px; line-height: 1.45; color: var(--base-700); }
.nt-item__meta { display: block; margin-top: 3px; font-size: var(--log-time-size); font-weight: var(--log-time-weight); color: var(--color-surface-pure); }

/* CTA dentro do item. Nem toda notificação tem — as que não têm são fato
   consumado e o item inteiro leva ao contexto. */
.nt-item__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 9px; }
.nt-item__cta {
  padding: 6px 13px; border-radius: var(--lkt-radius-pill);
  font-family: var(--theme-font-family-base); font-size: 12.5px; font-weight: 700;
  background: var(--lkt-primary-pure); color: var(--color-ivory);
  transition: background var(--dur) var(--ease);
}
.nt-item__cta:hover { background: var(--lkt-primary-dark); }
.nt-item__cta--ghost { background: var(--lkt-surface-pale); color: var(--base-700); }
.nt-item__cta--ghost:hover { background: var(--base-200); color: var(--base-800); }

/* Marcador de não lida. Ponto, não negrito: negrito na frase inteira derruba a
   hierarquia interna do item (quem fez o quê já usa negrito). */
.nt-item__unread {
  align-self: start; margin-top: 12px;
  width: 8px; height: 8px; border-radius: var(--lkt-radius-circular);
  background: var(--lkt-primary-pure);
}
.nt-item.is-read .nt-item__unread { visibility: hidden; }
.nt-item.is-read .nt-item__title { font-weight: 600; color: var(--base-700); }

.nt-panel__foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px;
  padding: 11px 16px; border-top: 1px solid var(--base-100);
}
.nt-panel__link {
  font-family: var(--theme-font-family-base); font-size: 12.5px; font-weight: 700; color: var(--lkt-primary-pure);
  transition: color var(--dur) var(--ease);
}
.nt-panel__link:hover { color: var(--lkt-primary-dark); text-decoration: underline; }
.nt-panel__link--muted { color: var(--base-600); }
.nt-panel__link--muted:hover { color: var(--base-800); }

/* Vazio — estado de sucesso, não de falta. */
.nt-empty { padding: 46px 28px; text-align: center; }
.nt-empty svg { width: 34px; height: 34px; margin: 0 auto 12px; display: block; fill: none; stroke: var(--base-400); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.nt-empty p { font-size: 13.5px; font-weight: 700; color: var(--base-700); }
.nt-empty small { display: block; margin-top: 4px; font-size: 12.5px; color: var(--base-600); font-weight: 600; }

/* ============================================================
   3 · Toast — a chegada
   ============================================================
   Ao lado do sino, empilhando para cima. Vida de 10 s com barra de progresso;
   o contador PAUSA no hover e no foco de teclado — um toast que some enquanto
   a pessoa lê a própria notificação é um bug de acessibilidade, não um recurso.
   ============================================================ */
.nt-toaster {
  position: fixed; z-index: 250;
  display: flex; flex-direction: column-reverse; gap: 10px;
  width: min(360px, calc(100vw - 32px));
  pointer-events: none;
}
.nt-toaster:empty { display: none; }

/* Papel branco, contorno leve e sombra alta: o toast se DESTACA da tela em vez
   de virar um bloco escuro sobre ela. Sobre a home imersiva (aubergine) e sobre
   as telas claras de trabalho ele lê igual — o que a versão escura não fazia,
   porque escuro sobre escuro é camuflagem, não ênfase.

   Cada filho declara linha E coluna. Deixar o auto-placement resolver com um
   item de linha explícita na mesma grade embaralha a ordem — foi o que jogou o
   título para a terceira coluna e o × para a segunda. */
.nt-toast {
  pointer-events: auto; position: relative; overflow: hidden;
  display: grid; grid-template-columns: 28px minmax(0, 1fr) 20px;
  column-gap: 11px; align-items: start;
  padding: 14px 15px 16px;
  background: var(--color-ivory); color: var(--base-800);
  border: 1px solid var(--base-200);
  border-radius: var(--lkt-radius-sm-14);
  box-shadow: var(--ds-light-high);
}

/* Disco tingido, como o dot do painel e o ícone do banner — um grau menor,
   porque o toast é passageiro e não deve pesar como um cartão fixo. */
.nt-toast__ic {
  grid-column: 1; grid-row: 1;
  width: 28px; height: 28px; border-radius: var(--lkt-radius-circular);
  display: grid; place-items: center;
}
.nt-toast__ic svg { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.nt-toast__title { grid-column: 2; grid-row: 1; padding-top: 4px; font-family: var(--theme-font-family-base); font-size: 13.5px; font-weight: 700; line-height: 1.4; color: var(--base-800); }
.nt-toast__title b { font-weight: 800; }
.nt-toast__body { grid-column: 2; grid-row: 2; margin-top: 3px; font-size: 12.5px; line-height: 1.5; color: var(--base-700); }
.nt-toast__actions { grid-column: 2; grid-row: 3; display: flex; gap: 8px; margin-top: 11px; }
.nt-toast__cta {
  padding: 6px 13px; border-radius: var(--lkt-radius-pill);
  font-family: var(--theme-font-family-base); font-size: 12.5px; font-weight: 700;
  background: var(--lkt-primary-pure); color: var(--color-ivory);
  transition: background var(--dur) var(--ease);
}
.nt-toast__cta:hover { background: var(--lkt-primary-dark); }

.nt-toast__close {
  grid-column: 3; grid-row: 1; display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: var(--lkt-radius-nano);
  color: var(--base-600);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.nt-toast__close svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.nt-toast__close:hover { background: var(--base-100); color: var(--base-800); }

/* Barra de vida. `scaleX` animado no compositor, sem reflow por quadro. */
.nt-toast__life {
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  transform-origin: left center; scale: 1 1;
  background: currentColor;
}
.nt-toast.is-running .nt-toast__life { animation: nt-life var(--nt-vida, 10s) linear forwards; }
.nt-toast:hover .nt-toast__life,
.nt-toast:focus-within .nt-toast__life { animation-play-state: paused; }
@keyframes nt-life { from { scale: 1 1; } to { scale: 0 1; } }

/* Severidade colore o disco do ícone e a barra de vida — o papel branco é
   constante, senão quatro toasts empilhados viram um semáforo. Sobre claro a
   cor vem do extremo escuro da rampa; era do extremo claro quando o fundo era
   escuro, e trocar o fundo sem trocar isto deixaria o ícone ilegível. */
.nt-toast--neutral .nt-toast__ic { background: var(--lkt-primary-tinted); color: var(--lkt-primary-pure); }
.nt-toast--neutral .nt-toast__life { color: var(--lkt-primary-pure); }
.nt-toast--success .nt-toast__ic { background: var(--lkt-success-tinted); color: var(--lkt-success-darker); }
.nt-toast--success .nt-toast__life { color: var(--lkt-success-darker); }
.nt-toast--warning .nt-toast__ic { background: var(--lkt-warning-tinted); color: var(--lkt-warning-darker); }
.nt-toast--warning .nt-toast__life { color: var(--lkt-warning-darker); }
.nt-toast--negative .nt-toast__ic { background: var(--lkt-destructive-tinted); color: var(--lkt-destructive-pure); }
.nt-toast--negative .nt-toast__life { color: var(--lkt-destructive-pure); }

.nt-toast.is-entering { animation: nt-toast-in 340ms var(--ease) both; }
.nt-toast.is-leaving { animation: nt-toast-out 220ms var(--ease) both; }
@keyframes nt-toast-in { from { opacity: 0; translate: -14px 6px; scale: .97; } to { opacity: 1; translate: 0 0; scale: 1; } }
@keyframes nt-toast-out { to { opacity: 0; translate: -10px 0; scale: .98; } }

/* ============================================================
   4 · Banner contextual — DS:Alert em largura de conteúdo
   ============================================================
   Estado, não evento: fica enquanto a condição existir. Por isso não some
   sozinho e por isso quase sempre tem CTA — banner sem saída é só um aviso
   que a pessoa aprende a ignorar.
   ============================================================ */
.nt-banners { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.nt-banners:empty { display: none; }

/* Na home a view tem padding 0 e o fundo imersivo é `position: fixed` com
   z-index -1. Sem respiro e empilhamento o cartão encosta nas bordas e some
   contra a arte — foi por parecer insolúvel que a home chegou a ficar barrada
   como hospedeira. Papel claro sobre aubergine é contraste, não conflito.
   O recuo copia o do `.home-hero__inner` (styles.css) em vez de inventar um:
   a home é full-bleed, então o afastamento do rail não vem de graça como nas
   outras views, e um padding próprio jogava o cartão para debaixo do rail. */
.view--home > .nt-banners {
  position: relative; z-index: 2; margin-bottom: 0;
  padding: 16px clamp(24px, 5vw, 64px) 0 calc(var(--rail-w) + 40px);
}
/* No mobile não há rail, mas há a barra superior FIXA. As outras views já
   reservam 76 px de topo para ela (styles.css); a home, que é full-bleed, não —
   e o banner ficava metade escondido atrás da barra. */
@media (max-width: 768px) { .view--home > .nt-banners { padding: 76px 14px 0; } }

.nt-banner {
  display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; gap: 14px; align-items: start;
  padding: 15px 16px;
  border: 1px solid var(--base-200); border-radius: var(--lkt-radius-sm-14);
  background: var(--color-ivory);
}
.nt-banner__ic { width: 38px; height: 38px; border-radius: var(--lkt-radius-circular); display: grid; place-items: center; }
.nt-banner__ic svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.nt-banner__txt { min-width: 0; padding-top: 2px; }
/* block: mesmos <span> empilháveis do item do painel — sem isto o título e o
   corpo viram uma frase só, colada. */
.nt-banner__title { display: block; font-family: var(--theme-font-family-base); font-size: 14px; font-weight: 800; color: var(--base-800); line-height: 1.35; }
.nt-banner__body { display: block; margin-top: 3px; font-size: 13px; line-height: 1.5; color: var(--base-700); }
.nt-banner__body b { font-weight: 800; color: var(--base-800); }
.nt-banner__side { display: flex; align-items: center; gap: 8px; padding-top: 2px; }
.nt-banner__cta {
  white-space: nowrap; padding: 8px 15px; border-radius: var(--lkt-radius-pill);
  font-family: var(--theme-font-family-base); font-size: 13px; font-weight: 700;
  background: var(--base-800); color: var(--color-ivory);
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.nt-banner__cta:hover { background: var(--base-900); transform: translateY(-1px); }
.nt-banner__close { display: grid; place-items: center; width: 30px; height: 30px; border-radius: var(--lkt-radius-nano); color: var(--base-600); transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
.nt-banner__close svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.nt-banner__close:hover { background: var(--base-100); color: var(--base-800); }

/* Progresso da esteira de ativação — o único banner que mostra avanço. */
.nt-banner__steps { display: flex; gap: 5px; margin-top: 10px; }
.nt-banner__step { flex: 1; height: 4px; border-radius: var(--lkt-radius-pill); background: var(--base-200); }
.nt-banner__step.is-done { background: var(--lkt-primary-pure); }

/* Variantes DS:Alert. O 5º caso que a gente sempre quer inventar ("novidade")
   NÃO existe: é Neutral com o ícone na cor da marca. */
.nt-banner--neutral { background: var(--lkt-surface-tinted); border-color: var(--base-200); }
.nt-banner--neutral .nt-banner__ic { background: var(--lkt-primary-tinted); color: var(--lkt-primary-pure); }
.nt-banner--success { background: var(--lkt-success-tinted); border-color: var(--lkt-success-pale); }
.nt-banner--success .nt-banner__ic { background: var(--color-ivory); color: var(--lkt-success-darker); }
.nt-banner--warning { background: var(--lkt-warning-tinted); border-color: var(--lkt-warning-pale); }
.nt-banner--warning .nt-banner__ic { background: var(--color-ivory); color: var(--lkt-warning-darker); }
.nt-banner--negative { background: var(--lkt-destructive-tinted); border-color: var(--lkt-destructive-pale); }
.nt-banner--negative .nt-banner__ic { background: var(--color-ivory); color: var(--lkt-destructive-pure); }
.nt-banner--negative .nt-banner__cta { background: var(--lkt-destructive-pure); }
.nt-banner--negative .nt-banner__cta:hover { background: var(--lkt-destructive-dark); }

/* Alerta global (incidente): não pertence a nenhuma view — é do sistema
   inteiro. Faixa fixa no topo, à direita do rail, presente em qualquer tela.
   NÃO ganha cor própria: usa as mesmas variantes de severidade dos demais. O
   que o distingue é a POSIÇÃO, não a paleta — um quinto tratamento de cor só
   ensinaria a pessoa a decodificar mais um código.
   (A primeira versão era escura como o toast, e sumia contra a home imersiva:
   fundo escuro sobre fundo escuro não é ênfase, é camuflagem.) */
/* Empilhamento do módulo, de baixo para cima (valores REAIS — este comentário
   dizia "240 painel" e o painel está em 180 desde que passou a dividir a faixa
   dos modais; quem seguisse a doc antiga e o subisse quebraria o "por debaixo"
   da barra em silêncio):
     180  painel         — mesma faixa dos modais do app
     181  barra do menu  — SÓ com o painel aberto e no modo rail (bloco 2c)
     200  faixa global   — é conteúdo de página, ainda que fixa
     230  teste          — ferramenta do protótipo
     250  toaster        — o mais efêmero fica por cima de tudo
   A faixa estava em 300 e cobria painel e toast: no mobile o toast abria
   inteiro debaixo dela. Aviso permanente não pode tapar aviso passageiro.
   PENDENTE (decisão do Gustavo): com faixa global no ar, ela cobre o cabeçalho
   do painel, que agora começa sempre na altura do topo da barra. Resolver exige
   escolher entre o painel descer (perde a mesma altura da barra nesse estado) e
   a faixa ficar por baixo (esconde alerta crítico) — nenhuma das duas é
   acabamento, as duas são decisão de produto. */
.nt-global {
  position: fixed; top: 12px; left: calc(var(--rail-w) + 32px); right: 24px; z-index: 200;
}
.nt-global:empty { display: none; }
.nt-banner--global {
  align-items: center;
  box-shadow: var(--ds-light-high);
}

/* A faixa não pode tapar o topo da tela que está embaixo. A classe entra no
   body só enquanto existir alerta global, então fora disso o espaçamento das
   views é exatamente o de antes. */
.nt-tem-global .view,
.nt-tem-global .adm-page { padding-top: 84px; }

.nt-banner.is-entering { animation: nt-banner-in 320ms var(--ease) both; }
@keyframes nt-banner-in { from { opacity: 0; translate: 0 -8px; } to { opacity: 1; translate: 0 0; } }

/* ============================================================
   5 · Teste das notificações — PROTÓTIPO, não faz parte do produto
   ============================================================
   Existe para provar cada estado sem esperar o evento real acontecer. No
   produto, nada disto sobe: o gatilho é o backend.
   ============================================================ */
/* ============================================================
   6 · Responsivo
   ============================================================ */
@media (max-width: 768px) {
  /* Sem rail: o sino mora na barra superior, e o painel vira folha de largura
     cheia ancorada abaixo dela. */
  .nt-panel { width: calc(100vw - 24px); max-height: calc(100vh - 150px); }
  .nt-toaster { width: calc(100vw - 24px); }
  .nt-banner { grid-template-columns: 32px minmax(0, 1fr); }
  .nt-banner__ic { width: 32px; height: 32px; }
  .nt-banner__side { grid-column: 1 / -1; padding-top: 4px; }
  .nt-banner__cta { flex: 1; text-align: center; }
  /* Sem rail no mobile: a faixa global ocupa a largura toda, abaixo da barra. */
  .nt-global { left: 12px; right: 12px; top: 64px; }
  /* As duas hospedeiras, não só a do professor: sem `.adm-page` aqui, o conteúdo
     do admin no mobile ficava atrás da faixa fixa. */
  .nt-tem-global .view,
  .nt-tem-global .adm-page { padding-top: 148px; }
}

.mobile-bar__bell { position: relative; display: grid; place-items: center; width: 36px; height: 36px; color: var(--base-700); }
.mobile-bar__bell svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.mobile-bar__actions { display: flex; align-items: center; gap: 10px; }

/* ============================================================
   7 · Movimento reduzido
   ============================================================
   A barra de vida é informação, não enfeite: sem animação ela vira uma barra
   cheia parada e o toast passa a fechar só no clique — nunca sozinho, porque
   sem a barra a pessoa perde o aviso de que o tempo está correndo.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .nt-bell.is-ringing svg,
  .nt-toast.is-entering, .nt-toast.is-leaving, .nt-banner.is-entering { animation: none; }
  .nt-toast.is-running .nt-toast__life { animation: none; }
  .nt-banner__cta:hover, .nt-item:hover { transform: none; }
}
