/* ============================================================================
   PALCO — a caixa de 1920x1080 que encolhe inteira em vez de refluir.
   Fonte de verdade: 02-arquitetura/02-design-system.md §4.3 e §4.4.

   Por que escalar e não refluir: um projetor de hotel pode ser 4:3, 16:10 ou
   1024x768. Refluir num deck ensaiado muda a posição de tudo e invalida o
   ensaio. Escalar mantém a composição pixel-idêntica e apenas põe barras na
   cor do fundo. O piso tipográfico de 32px continua legível quando escalado
   para 1024x768 (fica 17px numa tela que está a metade da distância).
   ========================================================================== */

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

/* --- A ESCALA DO DECK ----------------------------------------------------
   Todo o design system mede em rem, e rem é relativo à RAIZ — não ao palco.
   Pôr font-size no .stage escala só o que estiver em em/cqh, e o deck inteiro
   está em rem: sem esta regra o palco encolhe e o conteúdo não, e num projetor
   1280x720 um terço da cena fica fora da moldura, cortado pelo overflow.
   A conta é a mesma do .stage logo abaixo — a menor das duas razões é a que
   define o letterbox — só que aplicada à raiz. */
html {
  /* Literal local: 16 é quanto vale 1rem no palco de projeto. Não é token
     porque tokens.css o expressa implicitamente, ao medir tudo em rem sobre
     1920x1080; --stage-w e --stage-h, esses sim, vêm de lá. */
  --rem-projeto: 16;
  font-size: min(calc(100vw / var(--stage-w) * var(--rem-projeto)),
                 calc(100vh / var(--stage-h) * var(--rem-projeto)));
}
/* Em "preencher" o palco cobre a tela inteira e aceita cortar as bordas: a
   escala passa a ser a MAIOR das duas razões, senão sobraria moldura vazia.
   Restrito à projeção: no celular e no papel o palco não existe como palco, e
   este seletor é específico demais para os pinos de 16px lá embaixo vencerem. */
@media (min-width: 901px) {
  :root:has(.stage[data-fit="fill"]) {
    font-size: max(calc(100vw / var(--stage-w) * var(--rem-projeto)),
                   calc(100vh / var(--stage-h) * var(--rem-projeto)));
  }
}

html, body {
  margin: 0; padding: 0;
  height: 100%; width: 100%;
  background: var(--bg-900);
  color: var(--txt-high);
  font-family: var(--font-body);
  overflow: hidden;                /* nada rola numa apresentação (regra 17) */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body.presenting { cursor: none; }  /* cursor volta ao mover — ver deck.js     */

/* --- O palco -------------------------------------------------------------
   A caixa 16:9 com letterbox. O rem que escala junto está na regra html acima;
   o font-size daqui serve ao que mede em em dentro do palco.               */
.stage {
  /* Lado da miniatura de QR. Declarado no palco, e não em .qr-mini, porque o
     selo da S29 (scenes.css) se posiciona a partir dele e precisa enxergá-lo
     por herança. Não é token de design: é medida de um componente do chrome. */
  --qr-mini-lado: 4.5rem;   /* 72px = --margin-h (96) menos --sp-3 (24) */
  container-type: size;
  position: relative;
  aspect-ratio: 16 / 9;
  width:  min(100vw, calc(100vh * 16 / 9));
  height: min(100vh, calc(100vw * 9 / 16));
  margin: auto;                    /* letterbox automático fora de 16:9      */
  font-size: 1.4815cqh;
  overflow: hidden;
  background: var(--bg-900);
  isolation: isolate;
}

/* Modo "preencher" — corta as bordas em vez de deixar barras. Tecla Shift+F.
   Existe para o projetor exótico em que a moldura incomoda mais que o corte. */
.stage[data-fit="fill"] {
  width: 100vw; height: 100vh; aspect-ratio: auto;
  font-size: 1.4815cqh;
}

/* --- Cena ---------------------------------------------------------------- */
.scene {
  position: absolute;
  inset: 0;
  display: none;
  padding: var(--margin-v) var(--margin-h);
  opacity: 0;
}
.scene[data-state="active"]  { display: block; opacity: 1; }
.scene[data-state="leaving"] { display: block; opacity: 1; }

/* Entrada padrão de cena. Cenas com coreografia própria marcam data-anim="custom"
   e assumem a responsabilidade de aparecer. */
.scene[data-state="active"]:not([data-anim="custom"]) {
  animation: sceneIn var(--dur-fast) var(--ease-out-expo) both;
}
@keyframes sceneIn {
  from { opacity: 0; transform: translateY(1rem) }
  to   { opacity: 1; transform: none }
}

/* --- Grid de 12 colunas dentro da safe area ------------------------------ */
.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 0 var(--gutter);
  height: 100%;
}
.col-1  { grid-column: span 1 }   .col-2  { grid-column: span 2 }
.col-3  { grid-column: span 3 }   .col-4  { grid-column: span 4 }
.col-5  { grid-column: span 5 }   .col-6  { grid-column: span 6 }
.col-7  { grid-column: span 7 }   .col-8  { grid-column: span 8 }
.col-9  { grid-column: span 9 }   .col-10 { grid-column: span 10 }
.col-11 { grid-column: span 11 }  .col-12 { grid-column: span 12 }

/* Faixas horizontais canônicas — criam ritmo entre cenas (§4.4).
   Alturas relativas ao palco de 1080px: 72-180 / 180-300 / 300-880 / 880-1008 */
.band-eyebrow { min-height:  6.75rem }   /* 108px */
.band-title   { min-height:  7.5rem  }   /* 120px */
.band-content { min-height: 36.25rem }   /* 580px */
.band-data    { min-height:  8rem    }   /* 128px */

/* --- Barra de progresso persistente (nasce na S05) ----------------------- */
.progress {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: .25rem;                                  /* 4px */
  background: rgba(255,255,255,.08);
  z-index: 60; pointer-events: none;
  opacity: 0; transition: opacity var(--dur-fast);
}
.progress[data-visible="1"] { opacity: 1 }
.progress__fill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--primary), var(--primary-lift));
  transition: width var(--dur-base) var(--ease-out-expo);
}
.progress__demo {                                   /* o ponto da demo (Ato IV) */
  position: absolute; top: 50%; width: .625rem; height: .625rem;
  border-radius: var(--r-full); background: var(--accent);
  transform: translate(-50%, -50%);
  box-shadow: 0 0 12px var(--accent);
}

/* --- Miniaturas persistentes dos QR (ancoradas a partir da S04) ----------
   O lado é 4,5rem e não 7,5rem por uma conta de colisão: a miniatura começa a
   --sp-3 (24px) da borda, e a área segura da cena começa a --margin-h (96px).
   24 + 72 = 96 — a miniatura termina exatamente onde a cena começa. Com os
   120px antigos ela avançava 48px sobre a área segura e cobria o algarismo do
   .act-tag ("V · DEBRIEF" virava "· DEBRIEF") e o fim da marca d'água, em
   todas as cenas da S04 em diante.
   O lado mora numa custom property porque o selo da S29 se posiciona a partir
   dele, em scenes.css: os dois têm de mudar juntos ou nenhum. */
.qr-mini {
  position: absolute; top: var(--sp-3);
  width: var(--qr-mini-lado); height: var(--qr-mini-lado);
  border-radius: var(--r-md); background: #fff; padding: .5rem;
  opacity: 0; transform: scale(.72); pointer-events: none; z-index: 55;
  transition: opacity var(--dur-base), transform var(--dur-base);
}
/* O símbolo é gerado com viewBox e sem width/height (é o que o deixa escalar
   com o palco), então quem lhe dá tamanho é esta regra — sem ela o SVG inline
   assume os 300×150 do agente de usuário e vaza para fora da miniatura. */
.qr-mini svg { display: block; width: 100%; height: 100% }
.qr-mini[data-visible="1"] { opacity: .35 }
.qr-mini--wa   { left:  var(--sp-3) }
.qr-mini--deck { right: var(--sp-3) }

/* --- Cronômetro de palco (tecla `c`) --------------------------------------
   13/08/2026, pedido do palestrante. Discreto por especificação: mono, na
   escala de rótulo (24px) e em --txt-dim, que o design system reserva a
   ornamento. A 12 m de distância a plateia não lê; a 60 cm do notebook, ele
   lê. Ancora abaixo do QR mini da direita — faixa de chrome, sem conteúdo de
   cena em nenhuma das 34.

   O estado de ATRASO reaproveita os três checkpoints que o motor já calcula
   (deck.js › checkpointStatus): quando o relógio passa de um checkpoint sem a
   cena ter chegado, o mostrador vira âmbar. É a única informação nova que ele
   dá em relação ao presenter — e é a que decide corte no palco. */
.stage-clock {
  position: absolute; z-index: 58; pointer-events: none;
  top: calc(var(--sp-3) + var(--qr-mini-lado) + var(--sp-2));
  right: var(--sp-3);
  display: grid; justify-items: end; gap: .125rem;
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--r-sm);
  background: rgba(0, 0, 0, .28);
  font: 500 var(--fs-label)/1 var(--font-mono);
  color: var(--txt-dim);
  opacity: 0; transition: opacity var(--dur-fast);
}
.stage-clock[data-visible="1"] { opacity: .78 }
.stage-clock[data-late="1"] { color: var(--warn) }
.stage-clock__cena { font-size: 1rem; opacity: .7 }
@media (max-width: 900px), print { .stage-clock { display: none } }

/* --- Marca d'água HUMANIZADA (viaja da S06 até a S30) --------------------
   O recuo da direita sai da miniatura de QR, não da margem do palco: com
   `right: var(--margin-h)` a palavra encostava no cartão branco em toda cena
   do Ato III em diante, e duas coisas encostadas leem como uma sobreposta. */
.watermark-hz {
  position: absolute; top: var(--sp-4);
  right: calc(var(--sp-3) + var(--qr-mini-lado) + var(--sp-4));
  font: 700 var(--fs-label)/1 var(--font-display);
  letter-spacing: var(--tr-label); text-transform: uppercase;
  color: var(--accent); opacity: 0; z-index: 54; pointer-events: none;
  transition: opacity var(--dur-base);
}
.watermark-hz[data-visible="1"] { opacity: .18 }

/* --- Tela preta (tecla b) — para tirar a atenção do slide e ficar com ela - */
.blackout {
  position: fixed; inset: 0; background: #000; z-index: 999;
  opacity: 0; pointer-events: none; transition: opacity 180ms;
}
.blackout[data-on="1"] { opacity: 1; pointer-events: all }

/* --- Aviso de tela (js/deck.js: nível de corte, cronômetro, tema) ---------
   É recado do palestrante para si mesmo, e não conteúdo. Por isso mora no
   <body> e não no palco: fica no canto inferior direito da janela, sobre a
   barra do letterbox quando ela existe, e nunca por cima da composição de
   1920x1080. Como está fora do .stage, o rem aqui é o do documento (16px) e
   não o do palco — o tamanho é o mesmo em qualquer projetor, que é o que se
   quer de um aviso operacional: legível a um metro, ignorável a dez.
   Se a plateia reparar no toast, ele falhou. */
.toast {
  /* Literais locais: não há token de medida de linha nem de desfoque de vidro.
     34ch é a largura do aviso mais longo ("Corte nível 3 — N cenas fora") sem
     quebrar; 14px de desfoque é o mesmo peso de vidro dos cards do deck. */
  --toast-w:    34ch;
  --toast-blur: 14px;

  position: fixed; right: var(--sp-3); bottom: var(--sp-3); z-index: 900;
  max-width: var(--toast-w);
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--stroke-hi);
  border-radius: var(--r-full);
  background: var(--bg-700);
  backdrop-filter: blur(var(--toast-blur));
  box-shadow: var(--elev-2);
  color: var(--txt-mid);
  font: 500 var(--fs-ref)/1.25 var(--font-body);
  pointer-events: none;

  opacity: 0; transform: translateY(var(--sp-1));
  transition: opacity var(--dur-fast) var(--ease-out-expo),
              transform var(--dur-fast) var(--ease-out-expo);
}
.toast[data-on="1"] { opacity: 1; transform: none }

/* ============================================================================
   MODO MOBILE — o deck é público via QR (§4.9)
   Abaixo de 900px o palco abandona o formato slide e vira página de leitura.
   Cada cena ganha a fala do palestrante como texto, e as referências viram
   links reais. É isso que faz o QR valer a pena: quem escaneia leva a
   bibliografia, não uma foto de slide.
   ========================================================================== */
@media (max-width: 900px) {
  /* Aqui o palco deixa de ser palco e vira página: a escala de projeção sai do
     caminho e o rem volta ao valor do navegador, que é o que a régua tipográfica
     de celular deste bloco assume. */
  html { font-size: 16px }
  html, body { overflow: auto; height: auto }

  .stage {
    aspect-ratio: auto; height: auto; width: 100%;
    font-size: 16px; container-type: normal;
  }
  .scene {
    position: static; display: block; opacity: 1;
    min-height: auto; padding: 3rem 1.25rem;
    border-bottom: 1px solid var(--stroke);
    animation: none;
  }
  .grid { display: block; height: auto }
  [class^="col-"] { grid-column: auto }

  /* sem drift, sem névoa, sem conectores — nada disso lê num celular */
  .float { position: static; animation: none; margin-bottom: 1rem; transform: none }
  .fog-noise, .fog-veil, .fog-edge, .conn, .qr-mini, .watermark-hz { display: none }
  /* o toast é chrome de palco: quem lê no celular não navega por teclado */
  .progress, .toast { display: none }
  /* o espaçador da banda do eyebrow guarda ritmo do palco 1080p; na página de
     leitura ele é só faixa morta de ~108px (o .act-tag em fluxo já abre a cena) */
  .band-eyebrow { display: none }
  /* 13/08, revisão mobile (item F): o piso de 580px da banda é medida de
     palco — no fluxo virava vazio entre título e conteúdo (S03, S05, S06). */
  .band-content { min-height: 0 }

  :root {
    --fs-dxl: 3.25rem; --fs-d1: 2.75rem; --fs-d2: 2.125rem; --fs-d3: 1.75rem;
    --fs-h1: 1.5rem;   --fs-h2: 1.25rem; --fs-lg: 1.125rem;
    --fs-body: 1.0625rem; --fs-mono: 1.125rem; --fs-label: .8125rem;
    --fs-ref: .8125rem;
    /* --ref-band tem de ser reafirmado aqui, e NÃO pode ser deixado herdando
       o calc de tokens.css: com --margin-v: 0 (zero SEM unidade) o
       calc(0 + 3rem) é erro de tipo, a declaração `bottom` do
       .chip-callback--corner é descartada e o chip cai na posição estática —
       em cima do conteúdo da cena. Zero devolve o comportamento inofensivo:
       chip ancorado no pé do documento. ⚠ NÃO "consertar" dando unidade ao
       zero de --margin-v: o calc(0 - 2.5rem) do .scene__ref ficaria VÁLIDO em
       −2.5rem e arrastaria a citação das 15 cenas para o pé do documento —
       é a invalidez dele que faz a citação fluir certo no celular. */
    --margin-h: 0; --margin-v: 0; --ref-band: 0;
  }

  /* a fala do palestrante, escondida na projeção, visível no celular
     (na versão pública os .notes nem existem no HTML — build de 13/08) */
  .notes { display: block; margin-top: 1.5rem }
  .notes summary {
    cursor: pointer; font: 600 .875rem var(--font-body);
    color: var(--primary-soft); padding: .5rem 0;
  }
  .notes p { font-size: 1rem; line-height: 1.6; color: var(--txt-mid) }

  /* --- ÍNDICE DO MODO DE LEITURA (13/08/2026) ---------------------------
     A página tem ~57.000px; sem isto quem escaneia o QR não acha nada.
     O nav vive fora de .stage (é chrome de leitura); o botão flutuante
     volta a ele de qualquer ponto. Âncoras nativas: o motor está
     desativado abaixo de 900px (deck.js). */
  .leitura-indice {
    display: block; padding: 1.5rem 1.25rem 1rem;
    border-bottom: 1px solid var(--stroke); background: var(--bg-800);
  }
  .leitura-indice__tit {
    font: 700 .8125rem/1 var(--font-body); letter-spacing: .12em;
    text-transform: uppercase; color: var(--txt-low); margin: 0 0 .75rem;
  }
  .leitura-indice__links { display: flex; flex-wrap: wrap; gap: .5rem }
  .leitura-indice__links a {
    display: inline-block; padding: .5rem .875rem;
    border: 1px solid var(--stroke-hi); border-radius: var(--r-full);
    font: 500 .875rem/1.2 var(--font-body); color: var(--txt-mid);
    text-decoration: none; background: var(--bg-glass);
  }
  .leitura-topo {
    display: block; position: fixed; right: .875rem; bottom: .875rem; z-index: 60;
    padding: .625rem .875rem; border-radius: var(--r-full);
    border: 1px solid var(--stroke-hi); background: var(--bg-700);
    color: var(--txt-mid); font: 600 .8125rem/1 var(--font-body);
    text-decoration: none; box-shadow: var(--elev-2); opacity: .92;
  }
}
@media (min-width: 901px) { .notes, .leitura-indice, .leitura-topo { display: none } }

/* ============================================================================
   IMPRESSÃO — Ctrl+P gera um PDF de 31 páginas, uma por cena.
   Serve de backup físico e de material para quem pedir depois.
   ========================================================================== */
@media print {
  @page { size: 1920px 1080px; margin: 0 }
  /* A página impressa É o palco de projeto: rem volta a 16px fixos, senão a
     escala se amarraria ao viewport da janela que mandou imprimir. O segundo
     seletor cobre quem imprimiu com o modo "preencher" ligado. */
  html, :root:has(.stage[data-fit="fill"]) { font-size: 16px }
  html, body { overflow: visible; height: auto; background: #fff }
  .stage { width: 1920px; height: auto; aspect-ratio: auto; font-size: 16px }
  .scene {
    position: static; display: block !important; opacity: 1 !important;
    width: 1920px; height: 1080px; page-break-after: always;
    animation: none; break-inside: avoid;
  }
  .fog-noise, .fog-veil, .fog-edge, .qr-mini, .progress, .blackout, .toast { display: none }
  .float { animation: none }
}

/* ============================================================================
   MOVIMENTO REDUZIDO — respeitado por preferência do sistema e por tecla (m).
   Toda coreografia vira cross-fade de 200ms. O deck continua contando a mesma
   história; ele só para de se mexer.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 200ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 200ms !important;
  }
  .float { animation: none !important }
}
:root[data-motion="reduced"] .float { animation: none !important }
:root[data-motion="reduced"] *,
:root[data-motion="reduced"] *::before,
:root[data-motion="reduced"] *::after {
  animation-duration: 200ms !important;
  transition-duration: 200ms !important;
}
