/* ============================================================================
   Bruno Bento . Portfolio
   Conceito: "A junta" (the seam). Herdado do banner aprovado (banner-light.svg
   e banner-dark_preview.png). Toda cor, escala e ritmo abaixo foi extraido de
   la: os valores @1200px sao literalmente os do banner, que tem 1200x400.
   HTML + CSS + JS puro. Zero build, zero framework.

   Sumario
     1. Tokens
     2. Reset e base
     3. Utilitarios
     4. Hero: a chapa
     5. Lado humano (sans)
     6. A junta: costura e solda
     7. Lado maquina (mono)
     8. Movimento do hero
     9. Reduced motion
    10. Casos: a vitrine
   ========================================================================== */


/* ── 1. Tokens ─────────────────────────────────────────────────────────────
   Paleta: aco + uma faisca. Um unico acento ambar, com extrema parcimonia:
   no hero ele aparece no arco da solda, na seta do CTA e no foco. Nada mais. */

:root {
  color-scheme: light dark;

  /* --- superficies (banner-light.svg) --- */
  --surface-human:   #fbfcfd;  /* rect esquerdo: o lado humano, luz batendo */
  --surface-machine: #e9edf1;  /* rect direito: rebaixado, o lado maquina   */
  --seam:            #cfd7de;  /* a costura: sulco, mais escuro que os dois */
  --rule:            #cfd7de;  /* fios da ficha tecnica                     */

  /* --- tinta --- */
  --ink-strong: #0e1418;  /* nome                       */
  --ink:        #212a32;  /* titulo, itens da stack     */
  --ink-muted:  #59646f;  /* tagline, metadados, links  */

  /* --- acao --- */
  --cta-bg: #141a1f;
  --cta-fg: #f4f7f9;
  --accent: #ff8f45;      /* a faisca: seta do CTA sobre a pastilha escura   */
  --focus:  #a8490a;      /* mesma familia, escurecida p/ 3:1 sobre o claro  */

  /* --- o arco da solda (radialGradient #arc do banner) --- */
  --arc-core: #ffc880;
  --arc-mid:  rgba(244, 120, 15, .95);
  --arc-halo: rgba(210, 84, 10, .32);
  --arc-edge: rgba(210, 84, 10, 0);

  /* --- luz caindo do canto superior esquerdo (radialGradient #sheen) --- */
  --sheen: radial-gradient(95% 95% at 14% 0%,
             rgba(222, 230, 237, 0)    0%,
             rgba(222, 230, 237, .09) 55%,
             rgba(222, 230, 237, .22) 100%);

  /* --- sombra do rebaixo, logo depois da costura (linearGradient #seamShadow) --- */
  --recess-1: rgba(28, 40, 49, .10);
  --recess-2: rgba(28, 40, 49, 0);

  /* --- tipografia ---
     Fallback = as stacks exatas do banner. Se o webfont falhar, o site cai
     exatamente na renderizacao do banner. */
  --font-sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'IBM Plex Mono', 'SF Mono', 'Cascadia Code', 'JetBrains Mono', Consolas, 'Liberation Mono', monospace;

  /* Escala: o termo do meio de cada clamp e o vw que reproduz o banner em
     1200px de viewport (58px = 4.833vw, 27px = 2.25vw, 18px = 1.5vw...).
     Em 1200px o site e o banner tem a mesma tipografia, glifo por glifo. */
  --fs-display: clamp(2.375rem,   4.833vw, 5.5rem);    /* 58    @1200 */
  --fs-h2:      clamp(1.5rem,     2.917vw, 2.5rem);    /* 35    @1200 (proximas secoes) */
  --fs-h3:      clamp(1.125rem,   2.25vw,  2.125rem);  /* 27    @1200 */
  --fs-body:    clamp(.9375rem,   1.5vw,   1.25rem);   /* 18    @1200 */
  --fs-mono-lg: clamp(1rem,       1.667vw, 1.375rem);  /* 20    @1200 */
  --fs-mono-sm: clamp(.8125rem,   1.375vw, 1.0625rem); /* 16.5  @1200 */

  /* Ritmo: idem, medido no banner (padding 64, texto a 40 da costura...) */
  --pad-x:    clamp(1.25rem,  5.333vw, 8rem);     /* 64 @1200 */
  --pad-seam: clamp(1.25rem,  3.333vw, 5rem);     /* 40 @1200 */
  --pad-y:    clamp(2rem,     6vw,     4.5rem);   /* 72 @1200 */
  --recess-w: clamp(1.75rem,  4.667vw, 4.5rem);   /* 56 @1200 */
  --sheet-max: clamp(17.5rem, 30vw,    26.25rem); /* 360 @1200 */

  /* Respiro entre secoes. Maior que --pad-y: o hero e uma peca inteira, uma
     secao de leitura precisa de mais ar em volta. */
  --pad-section: clamp(3rem, 9vw, 7rem);          /* 108 @1200 */

  /* Onde a costura cai. O hero resolve isso pela grade (63.33fr / 36.67fr);
     daqui pra baixo as secoes precisam do numero para desenhar a costura na
     mesma coluna. Um valor so, duas leituras: se mudar, muda em toda a pagina. */
  --seam-x: 63.33%;

  /* Medida da coluna humana. A tela de 1200 nao encosta nisso (a coluna da
     760 - 64 - 40 = 656); o teto existe para 1600px+ nao esticar a linha. */
  --case-max: 48rem;   /* 768 */

  /* altura do card no baralho; e tambem o trajeto vertical da solda */
  --carta-h: min(82vh, 58rem);

  /* Raio: a pastilha e pill (rx = h/2, como no banner). O raio da chapa fica
     registrado para as superficies das proximas secoes. */
  --r-pill:  999px;
  --r-plate: 22px;

  /* Movimento. A curva e a mesma do banner (keySplines .23 1 .32 1), que por
     acaso e o strong ease-out do Emil Kowalski. */
  --ease-out: cubic-bezier(.23, 1, .32, 1);
  --t-fast:   160ms;
  --t-reveal: 500ms;

  /* Dimensao do arco: fixa. E uma tocha, uma ferramenta fisica; nao cresce
     com a janela. 36x96 = o ellipse rx18 ry48 do banner, 1:1.
     Mobile-first: com a junta deitada, o arco deita junto. Mora no :root
     porque a tocha e o arco precisam ler os dois o mesmo valor. */
  --arc-w: 96px;
  --arc-h: 36px;
}

@media (min-width: 900px) {
  :root {
    --arc-w: 36px;
    --arc-h: 96px;
  }
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Amostrados pixel a pixel de banner-dark_preview.png (o .svg dark nao
       existe mais no repo; o PNG e a unica fonte da versao escura). */
    --surface-human:   #171c22;
    --surface-machine: #0e1217;
    --seam:            #29313b;  /* no escuro a costura e o cordao de solda
                                    pegando luz: mais clara que as duas faces */
    --rule:            #20262f;

    --ink-strong: #f1f5f8;
    --ink:        #d5dde5;
    --ink-muted:  #93a0ac;

    --cta-bg: #e9eef2;
    --cta-fg: #141a1f;
    --accent: #a8490a;   /* a pastilha inverte, a faisca escurece p/ contraste */
    --focus:  #ff8f45;

    --sheen: radial-gradient(95% 95% at 14% 0%,
               rgba(199, 215, 231, .07)  0%,
               rgba(199, 215, 231, .028) 55%,
               rgba(199, 215, 231, 0)    100%);

    --recess-1: rgba(0, 0, 0, .30);
    --recess-2: rgba(0, 0, 0, 0);
  }
}


/* ── 2. Reset e base ──────────────────────────────────────────────────────── */

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

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

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--surface-human);
  color: var(--ink);
  font-family: var(--font-sans);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

/* Zera a margem de tudo que a pagina usa. Ritmo vertical aqui e sempre
   declarado, nunca herdado do navegador. */
h1, h2, h3, h4, h5, p, ul, dl, dd, figure { margin: 0; }
ul { padding: 0; list-style: none; }

a { color: inherit; }

:where(a, button):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}


/* ── 3. Utilitarios ───────────────────────────────────────────────────────── */

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Base das proximas secoes. Hoje os alvos das ancoras nao tem altura: a
   pagina e so o hero. A folga de rolagem ja fica certa para quando tiverem. */
.section { scroll-margin-top: var(--pad-y); }


/* ── 4. Hero: a chapa ─────────────────────────────────────────────────────── */

.hero {
  display: grid;
  /* Mobile: a junta esta deitada. Mesmos 63/37, girados 90 graus. */
  grid-template-rows: minmax(min-content, 63.33fr) minmax(min-content, 36.67fr);

  /* agora e um card na grade */
  border: 1px solid var(--rule);
  border-radius: var(--r-plate);
  overflow: clip;
}

@media (min-width: 900px) {
  .hero {
    grid-template-rows: none;
    grid-template-columns: minmax(0, 63.33fr) minmax(0, 36.67fr);
  }
}


/* ── 5. Lado humano (sans) ────────────────────────────────────────────────── */

.human {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--pad-y) var(--pad-x);
  background-color: var(--surface-human);
  background-image: var(--sheen);
}

@media (min-width: 900px) {
  .human { padding-right: var(--pad-seam); }
}

.human__name {
  font-size: var(--fs-display);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -.024em;   /* -1.4px sobre 58px, do banner */
  color: var(--ink-strong);
  text-wrap: balance;
}

.human__role {
  margin-top: clamp(.25rem, .5vw, .5rem);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.007em;   /* -0.2px sobre 27px */
  color: var(--ink);
  text-wrap: balance;
}

.human__tagline {
  margin-top: clamp(.75rem, 1.667vw, 1.5rem);
  max-width: 32em;           /* ~560px @18px: a mesma medida de linha do banner */
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.5;          /* 27/18, do banner */
  color: var(--ink-muted);
  text-wrap: pretty;
}

.human__act { margin-top: clamp(1.375rem, 2.917vw, 2.5rem); }

.cta {
  display: inline-flex;
  align-items: center;
  gap: .75rem;
  min-height: clamp(2.75rem, 4.333vw, 3.5rem);   /* 52 @1200 */
  padding-inline: clamp(1.125rem, 2.167vw, 1.75rem);
  border-radius: var(--r-pill);
  background: var(--cta-bg);
  color: var(--cta-fg);
  font-size: clamp(.9375rem, 1.5vw, 1.125rem);
  font-weight: 600;
  letter-spacing: -.006em;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--t-fast) var(--ease-out);
}

/* A seta e a faisca. No banner ela aponta pra direita, levando ao site;
   aqui ela aponta pra baixo, levando pra dentro da pagina. */
.cta__arrow {
  color: var(--accent);
  transition: transform 200ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .cta:hover { transform: translateY(-1px); }
  .cta:hover .cta__arrow { transform: translateY(2px); }
}

.cta:active { transform: translateY(0) scale(.98); }


/* ── 6. A junta: costura e solda ──────────────────────────────────────────── */

/* A costura mora dentro do painel maquina, colada na borda de ataque dele.
   Assim ela cai exatamente no limite dos dois mundos em qualquer largura,
   sem depender de calcular porcentagem. */

.seam {
  position: absolute;
  background: var(--seam);
  /* mobile: deitada, no topo do painel */
  top: 0; left: 0; right: 0;
  height: 1.5px;
  transform-origin: left;
}

/* A tocha: uma janela do tamanho exato da costura. E ela que recorta o arco,
   fazendo o papel do clipPath #plate do banner, e impede que o arco crie
   overflow na pagina no fim do trajeto. */
.torch {
  position: absolute;
  overflow: clip;
  pointer-events: none;
  left: 0; right: 0;
  top: calc(.75px - (var(--arc-h) / 2));
  height: var(--arc-h);
}

.arc {
  position: absolute;
  top: 0;
  left: calc(var(--arc-w) / -2);
  width: var(--arc-w);
  height: var(--arc-h);
  opacity: 0;                /* estado base = apagado: sem animacao/reduced-motion nao mostra faisca */
  background: radial-gradient(ellipse closest-side,
    var(--arc-core) 0%,
    var(--arc-mid) 16%,
    var(--arc-halo) 50%,
    var(--arc-edge) 100%);
}

@media (min-width: 900px) {
  .seam {
    top: 0; bottom: 0; right: auto;
    width: 1.5px; height: auto;
    transform-origin: top;
  }

  .torch {
    top: 0; bottom: 0; right: auto;
    height: auto;
    left: calc(.75px - (var(--arc-w) / 2));
    width: var(--arc-w);
  }

  .arc {
    left: 0;
    top: calc(var(--arc-h) / -2);
  }
}


/* ── 7. Lado maquina (mono) ───────────────────────────────────────────────── */

.machine {
  position: relative;        /* ancora da costura e da tocha */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(1.25rem, 6vw, 4.5rem) var(--pad-x);
  background-color: var(--surface-machine);
  background-image: linear-gradient(180deg, var(--recess-1), var(--recess-2) var(--recess-w));
  font-family: var(--font-mono);
}

@media (min-width: 900px) {
  .machine {
    padding: var(--pad-y) var(--pad-seam);
    background-image: linear-gradient(90deg, var(--recess-1), var(--recess-2) var(--recess-w));
  }
}

.sheet { width: 100%; }

@media (min-width: 900px) {
  .sheet { max-width: var(--sheet-max); }
}

.sheet__lead {
  font-size: var(--fs-mono-sm);
  font-weight: 400;
  line-height: 1.35;
  color: var(--ink-muted);
}

/* Os dois fios agrupam a stack. Sao dois no total, nao um por linha. */
.sheet__stack {
  margin-top: clamp(.75rem, 1.833vw, 1.375rem);   /* 22 @1200: baseline ao fio */
  padding-top: clamp(1rem, 2.333vw, 1.75rem);     /* 28 @1200: fio ao React    */
  border-top: 1px solid var(--rule);
  font-size: var(--fs-mono-lg);
  font-weight: 500;
  line-height: 1.2;      /* travado: e ele que fecha o passo de 38px do banner */
  color: var(--ink);

  /* mobile: a lista deita, como todo o resto do painel */
  display: flex;
  flex-wrap: wrap;
  gap: .5rem clamp(1.25rem, 6vw, 2.25rem);
}

@media (min-width: 900px) {
  .sheet__stack {
    display: grid;
    /* 24px de linha (20 x 1.2) + 14 de gap = o passo de 38px do banner */
    gap: clamp(.5rem, 1.167vw, 1rem);
  }
}

.sheet__meta {
  margin-top: clamp(.875rem, 2.333vw, 1.75rem);
  padding-top: clamp(.875rem, 2.333vw, 1.75rem);
  border-top: 1px solid var(--rule);
  font-size: var(--fs-mono-sm);
  font-weight: 400;
  color: var(--ink-muted);
}

.sheet__loc { line-height: 1.45; }

.sheet__links {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem clamp(1.125rem, 2.5vw, 1.875rem);
  margin-top: clamp(.5rem, 1.167vw, .875rem);
}

.sheet__links a {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  color: var(--ink-muted);
  text-decoration: none;
  transition: color var(--t-fast) ease;
}

.sheet__links svg { flex: none; }

@media (hover: hover) and (pointer: fine) {
  .sheet__links a:hover {
    color: var(--ink-strong);
    text-decoration: underline;
    text-underline-offset: 3px;
  }
}


/* ── 8. Movimento ─────────────────────────────────────────────────────────────
   Uma ousadia so: a solda. A faisca desce e sobe a costura em loop (~4,5s
   ida-e-volta) — igual ao banner (decisao 2026-07-22). So a faisca faz loop;
   os reveals de texto e o desenho da costura entram uma vez e congelam.
   Os tempos abaixo sao os do banner convertidos de keyTimes para ms, para o
   site e o banner abrirem no mesmo compasso.
   Regra do estado base: tudo ja esta no estado FINAL no CSS. As animacoes so
   fornecem o estado inicial (keyframe `from`). Se elas nao rodarem, por
   reduced-motion ou por qualquer outro motivo, o hero aparece completo. */

.reveal {
  animation: reveal var(--t-reveal) var(--ease-out) var(--delay, 0ms) both;
}

@keyframes reveal {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
}

/* O lado humano entra primeiro. */
.human__name    { --delay: 300ms; }
.human__role    { --delay: 380ms; }
.human__tagline { --delay: 460ms; }
.human__act     { --delay: 580ms; }

/* O lado maquina acende depois, atras do arco que esta descendo: a solda
   passa e energiza a ficha. */
.sheet__lead                { --delay: 720ms; }
.sheet__stack li:nth-child(1) { --delay: 780ms; }
.sheet__stack li:nth-child(2) { --delay: 830ms; }
.sheet__stack li:nth-child(3) { --delay: 880ms; }
.sheet__meta                { --delay: 1020ms; }

/* A costura desenha de cima para baixo. Linear de proposito: uma tocha de
   solda anda com avanco constante, nao desacelera no fim. */
.seam { animation: seam-draw-x 954ms linear 243ms both; }

@keyframes seam-draw-x { from { transform: scaleX(0); } }
@keyframes seam-draw-y { from { transform: scaleY(0); } }

/* O arco viaja junto com a ponta da costura. Duas animacoes, porque o trajeto
   e o brilho tem tempos diferentes no banner, e cada uma toca uma propriedade
   diferente (transform / opacity), entao nao brigam. */
/* O arco acende uma vez e FICA; depois desce e SOBE a costura, pra sempre.
   Duas animacoes, propriedades diferentes (opacity / posicao), nao brigam:
   `weld-ignite` congela em opacity:1 -> o arco fica visivel durante o vai-e-vem;
   `weld-shuttle-*` viaja de 8% a 92% do vao da costura (nunca some nas pontas; a
   .torch clipa o resto) e volta, com ease-in-out pra reverter suave em cada ponta. */
.arc {
  animation:
    weld-ignite    600ms  linear      150ms both,
    weld-shuttle-x 4500ms ease-in-out 150ms infinite;
}

@keyframes weld-ignite {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* mobile: a costura e horizontal (topo do painel) -> vai-e-vem no eixo X */
@keyframes weld-shuttle-x {
  0%, 100% { left: calc(8%  - var(--arc-w) / 2); }
  50%      { left: calc(92% - var(--arc-w) / 2); }
}

/* desktop: a costura e vertical -> vai-e-vem no eixo Y (desce e sobe) */
@keyframes weld-shuttle-y {
  0%, 100% { top: calc(8%  - var(--arc-h) / 2); }
  50%      { top: calc(92% - var(--arc-h) / 2); }
}

@media (min-width: 900px) {
  .seam { animation-name: seam-draw-y; }
  .arc  { animation-name: weld-ignite, weld-shuttle-y; }
}

/* Enquanto a fonte nao chegou, a peca fica parada no primeiro quadro.
   Ver o script inline no <head>. */
.type-pending .reveal,
.type-pending .seam,
.type-pending .arc { animation-play-state: paused; }


/* ── 9. Reduced motion ────────────────────────────────────────────────────────
   Aqui e CSS, entao da pra desligar de verdade, diferente do SMIL do banner.
   Cirurgico: cai todo o deslocamento e a solda, ficam as transicoes de cor. */

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .seam,
  .arc { animation: none; }

  .torch { display: none; }

  .cta { transition: none; }
  .cta:hover,
  .cta:active { transform: none; }
  .cta:hover .cta__arrow { transform: none; }
}


/* ── 10. Baralho no scroll: passar de card em card ────────────────────────────
   Rolar pra baixo "puxa" o card da frente pra cima e revela o proximo
   (1 -> 2 -> 3); rolar pra cima desfaz (3 -> 2 -> 1). O baralho fica preso na
   tela (sticky) e o scroll conduz a animacao (JS so escreve transform/opacity).
   Fallback sem JS ou com movimento reduzido: os cards viram uma coluna. */

/* --- fallback: coluna simples --- */
.baralho { display: contents; }

.palco {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  max-width: 72rem;
  margin-inline: auto;
  padding: clamp(1.5rem, 4vw, 3rem) clamp(1rem, 3vw, 2rem);
}

.carta > * { height: var(--carta-h); }

/* o scroll segue o mouse: sobre a demo, rola o site interno dela; fora (margens,
   barra do card, ou o card de apresentacao) rola o portfolio (o baralho). Por
   isso a demo fica interativa (pointer-events no padrao), sem override aqui. */

/* --- modo scroll-scrub (com JS e movimento normal) --- */
@media (prefers-reduced-motion: no-preference) {
  html.js .rolo { position: relative; }   /* a altura vem do JS: N x 100vh */

  html.js .palco {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100dvh;
    display: grid;
    place-items: center;
    overflow: hidden;
    max-width: none;
    margin: 0;
    gap: 0;
    padding: clamp(1rem, 3vw, 2rem);
  }

  html.js .baralho {
    display: block;
    position: relative;
    width: min(72rem, 100%);
    height: var(--carta-h);
  }

  html.js .carta {
    position: absolute;
    inset: 0;
    transform-origin: center;
    will-change: transform, filter;
  }

  html.js .carta > * { height: 100%; }
}


/* --- a janela --- */

.janela {
  margin: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface-machine);
  border: 1px solid var(--rule);
  border-radius: var(--r-plate);
  overflow: clip;
  box-shadow: 0 12px 40px rgba(14, 20, 24, .18);
}

/* --- a barra de titulo: nome . setor --- */
.janela__bar {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex: none;
  padding: .625rem .75rem .625rem 1.125rem;
  background: var(--surface-human);
  border-bottom: 1px solid var(--rule);
}

.janela__label {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: .5rem;
  overflow: hidden;
  white-space: nowrap;
}

.janela__name {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: -.006em;
  color: var(--ink-strong);
  flex: none;
}

.janela__sep { color: var(--ink-muted); flex: none; }

.janela__setor {
  font-family: var(--font-mono);
  font-size: var(--fs-mono-sm);
  color: var(--ink-muted);
  overflow: hidden;
  text-overflow: ellipsis;
}

.janela__ext {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  color: var(--ink-muted);
  transition: background var(--t-fast) ease, color var(--t-fast) ease;
}

@media (hover: hover) and (pointer: fine) {
  .janela__ext:hover { background: var(--surface-machine); color: var(--ink-strong); }
}

/* --- o conteudo: a demo dentro do iframe --- */
.janela__viewport {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  background: var(--surface-human);
}

.janela__page {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.janela__loading {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: var(--fs-mono-sm);
  color: var(--ink-muted);
}



/* --- mobile: a janela encolhe, mas segue navegavel --- */
@media (max-width: 640px) {
  .janela { border-radius: 14px; }
}


/* ── 11. Preview da janela (mobile) ───────────────────────────────────────────
   No desktop (aprovado) a demo roda ao vivo no <iframe>. No celular um iframe
   de pagina desktop vira armadilha: scroll aninhado e conteudo minusculo. Entao
   no mobile a janela troca pra um preview limpo com botao grande que abre a demo
   em TELA CHEIA (nova aba). Estado base = escondido; a media query mobile mostra.
   Anima so transform/opacity; reduced-motion coberto. */

.janela__preview {
  display: none;                 /* desktop: some; mobile: flex (secao 12) */
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  text-align: center;
  min-height: 300px;
  padding: clamp(2rem, 8vw, 3rem) 1.5rem;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(255, 143, 69, .06), transparent 60%),
    var(--surface-machine);
}

.janela__glyph {
  width: 60px; height: 60px;
  display: grid; place-items: center;
  border-radius: 16px;
  color: var(--ink);
  background: var(--surface-human);
  border: 1px solid var(--rule);
}
.janela__glyph svg { width: 28px; height: 28px; }

.janela__ptxt {
  max-width: 22ch;
  font-family: var(--font-mono);
  font-size: var(--fs-mono-sm);
  line-height: 1.45;
  color: var(--ink-muted);
}

.janela__cta {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  min-height: 52px;              /* alvo de toque folgado (>= 44px) */
  padding: 0 1.6rem;
  border-radius: var(--r-pill);
  background: var(--cta-bg);
  color: var(--cta-fg);
  font-family: var(--font-sans);
  font-size: 1rem;              /* 16px: sem surpresa de zoom */
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--t-fast) var(--ease-out);
}
.janela__cta svg { width: 18px; height: 18px; color: var(--accent); }
.janela__cta:active { transform: scale(.98); }

@media (prefers-reduced-motion: reduce) {
  .janela__cta { transition: none; }
  .janela__cta:active { transform: none; }
}


/* ── 12. Mobile (<= 768px): o baralho vira coluna, a janela vira preview ───────
   SO mobile. O desktop (>= 769px) foi aprovado e nao e tocado por nada abaixo.
   Mobile-first (as 4 skills): 100dvh no lugar de h-screen (o palco ja usa dvh),
   1 coluna, alvos >= 44px, inputs 16px, grid em vez de flex-math, zero
   overflow horizontal, safe-area. O scroll-scrub e desligado aqui e no JS. */

@media (max-width: 768px) {
  /* nada de scroll horizontal preso: a pagina rola vertical, natural */
  body { overflow-x: hidden; }

  /* desliga o modo scroll-scrub e volta pra coluna empilhada.
     Repete os seletores html.js pra bater a especificidade do bloco de cima. */
  html.js .rolo { position: static; height: auto; }

  html.js .palco {
    position: static;
    height: auto;
    display: block;
    overflow: visible;
    max-width: 46rem;
    margin-inline: auto;
    padding: clamp(1rem, 5vw, 1.75rem);
    gap: 0;
  }

  html.js .baralho {
    display: block;
    position: static;
    width: auto;
    height: auto;
  }

  html.js .carta {
    position: static;
    inset: auto;
    transform: none;
    filter: none;
    will-change: auto;
    margin-bottom: clamp(1.25rem, 5vw, 1.75rem);
  }
  html.js .carta:last-child { margin-bottom: 0; }

  /* altura livre: o hero cresce com o conteudo; a janela idem */
  .carta > *,
  html.js .carta > * { height: auto; }

  /* a janela mostra a demo AO VIVO no celular (o layout mobile da propria demo),
     mas TRAVADA (pointer-events:none) pra o scroll da pagina passar; o botao
     "Abrir demo" (barra sobreposta) abre em tela cheia pra interagir. */
  .janela__viewport { flex: none; height: min(60vh, 460px); }
  .janela__page { display: block; pointer-events: none; }
  .janela__loading { display: none; }
  .janela__preview {
    display: flex; flex-direction: row; align-items: center; justify-content: center;
    position: absolute; left: 0; right: 0; bottom: 0; min-height: 0; gap: .5rem;
    padding: .7rem 1rem calc(.7rem + env(safe-area-inset-bottom));
    background: linear-gradient(to top, rgba(8,10,13,.8), rgba(8,10,13,0));
    z-index: 4; pointer-events: none;
  }
  .janela__glyph, .janela__ptxt { display: none; }
  .janela__cta { pointer-events: auto; }

  /* alvo de toque maior no botao de abrir-em-nova-aba da barra de titulo */
  .janela__ext { width: 44px; height: 44px; }

  /* EFEITO DE CARD no celular: cada card sobe e aparece ao entrar na tela.
     So liga com JS (classe html.mrev); sem JS os cards ficam visiveis. */
  html.mrev .carta {
    opacity: 0; transform: translateY(26px) scale(.985);
    transition: opacity .6s var(--ease-out), transform .6s var(--ease-out);
  }
  html.mrev .carta.in-view { opacity: 1; transform: none; }
}


/* ── 13. Snap do deck + pontos + DARK travado ─────────────────────────────────
   (a) transicao firme e curta do deck (so transform/opacity, ease-out do banner)
   (b) pontos de posicao (affordance da navegacao snap), criados via JS no desktop
   (c) portfolio SEMPRE em dark, independente do tema do device (igual ao print).
   As demos nos <iframe> mantem o visual proprio delas (documento separado). */

/* (c) DARK sempre: a ultima declaracao de cada token no :root vence a cascata,
   entao os valores escuros valem tanto no modo claro quanto no escuro do SO. */
:root {
  color-scheme: dark;

  --surface-human:   #171c22;
  --surface-machine: #0e1217;
  --seam:            #29313b;
  --rule:            #20262f;

  --ink-strong: #f1f5f8;
  --ink:        #d5dde5;
  --ink-muted:  #93a0ac;

  --cta-bg: #e9eef2;
  --cta-fg: #141a1f;
  --accent: #a8490a;
  --focus:  #ff8f45;

  --sheen: radial-gradient(95% 95% at 14% 0%,
             rgba(199, 215, 231, .07)  0%,
             rgba(199, 215, 231, .028) 55%,
             rgba(199, 215, 231, 0)    100%);

  --recess-1: rgba(0, 0, 0, .30);
  --recess-2: rgba(0, 0, 0, 0);

  /* duracao da troca de card no deck (JS usa 420ms igual) */
  --t-deck: 420ms;
}

/* (a) snap: a troca entre cards e uma transicao curta e firme, so no desktop.
   O JS escreve transform/opacity por indice; o CSS faz o tween. */
@media (prefers-reduced-motion: no-preference) and (min-width: 769px) {
  html.js .carta {
    transition: transform var(--t-deck) var(--ease-out),
                opacity   var(--t-deck) var(--ease-out);
  }
}

/* (b) pontos: indicador de posicao do deck (JS injeta no desktop) */
.deck-dots {
  position: fixed;
  right: clamp(10px, 1.6vw, 22px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 11px;
}
.deck-dots button {
  width: 10px;
  height: 10px;
  padding: 0;
  border: 0;
  cursor: pointer;
  border-radius: 50%;
  background: var(--rule);
  opacity: .5;
  transition: transform var(--t-fast) var(--ease-out),
              opacity var(--t-fast) ease,
              background var(--t-fast) ease;
}
@media (hover: hover) and (pointer: fine) {
  .deck-dots button:hover { opacity: 1; }
}
.deck-dots button[aria-current="true"] {
  background: var(--ink-muted);
  opacity: 1;
  transform: scale(1.35);
}
.deck-dots button:active { transform: scale(1.1); }

@media (prefers-reduced-motion: reduce) {
  .deck-dots button { transition: none; }
}
