/* ===========================================================================
   Projects — carrossel de cards + drawer de detalhe
   Compartilhado pela home e /testes/prototipo-nova-home. O
   arquivo é carregado DEPOIS de main.css + flat-type.css e só adiciona
   classes com prefixo `p` (`.pcard`, `.pjt`, `.pdrawer`, `.pgal`). Nenhuma
   regra dos componentes existentes é sobrescrita.

   Origem das medidas: Figma `Oktavio` (H0X3JmAFN32LWINqemEhXs) —
   card 124:562, seção 124:1280, modal 133:248. Onde o frame não diz
   (motion, foco, reduced-motion, breakpoints), vale produção, e o desvio
   está comentado na regra.

   As variantes usam atributos em <html>, trocáveis apenas no protótipo: `data-proto-carousel` (bleed|column), `data-proto-surface`
   (drawer|modal) e `data-proto-hover` (ring|fill). É o jeito de decidir
   olhando em vez de no texto; na home ficam bleed/drawer/ring.
   =========================================================================== */

:root {
  /* Medidas do frame que ainda não são token de produção. Ficam com escopo
     de componente (o precedente é `--panel-w`/`--cpanel-w` em spacing.css) e
     compartilhadas pela home e pelo protótipo. */
  --pcard-w: 266px;
  --pcard-h: 332px;
  --pcard-mark: 64px;
  --pshot-h: 400px;
  --pdrawer-w: 1000px;
  /* Passo do carrossel: um card + o gap da lista. */
  --pjt-step: calc(var(--pcard-w) + var(--space-16));
}

/* ---------------------------------------------------------------------------
   A seção Projects — cabeçalho (título + setas) e a trilha do carrossel.
--------------------------------------------------------------------------- */
.pjt__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-16);
  /* As margens de seção do h2 vão para o cabeçalho inteiro, incluindo setas. */
  margin-top: var(--space-72);
  margin-bottom: var(--space-24);
}
@media (max-width: 560px) {
  .pjt__head {
    margin-top: var(--space-64);
  }
}
.pjt__head h2 {
  margin-top: 0;
  margin-bottom: 0;
}
/* Pílula das setas (frame 124:1283): fundo --bg dentro de uma página --bg, o
   que a deixa legível só pela borda. É o desenho do Figma; o contraste real
   quem carrega é o botão ativo, em --white. */
.pjt__arrows {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  border: var(--border-w) solid var(--line);
  border-radius: var(--radius-full);
  background: var(--bg);
}
.pjt__arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4) var(--space-8);
  border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--faint);
  cursor: pointer;
  /* Só a cor e o fundo reagem. Sem transform: a seta não deve pular quando
     habilita/desabilita no meio de um scroll. */
  transition:
    background-color var(--duration-120) var(--ease),
    color var(--duration-120) var(--ease);
}
/* Habilitado = fundo --white e seta --ink (frame: Next Button Container).
   Desabilitado = sem fundo e seta --faint (frame: Previous). O estado nasce
   do scroll da trilha, não de um índice — ver prototipo.mjs. */
.pjt__arrow:not([disabled]) {
  background: var(--white);
  color: var(--ink);
}
.pjt__arrow[disabled] {
  cursor: default;
}
.pjt__arrow:focus-visible {
  outline: var(--border-w) solid var(--ink);
  outline-offset: var(--space-2);
}
/* A seta pixelada (componente `Arrow Pixelate`, 110:325): cinco quadrados de
   2px numa caixa de 14×16, desenhados com box-shadow a partir de um único
   pseudo-elemento — o mesmo truque de "arte em CSS" custa menos que cinco
   spans e mantém a cor em `currentColor`, então herda o estado do botão. */
.pjt__arrow svg {
  display: block;
  width: var(--space-14);
  height: var(--space-16);
}
.pjt__arrow--prev svg {
  transform: scaleX(-1);
}

/* A trilha. `overflow-x: auto` + scroll-snap: as setas empurram o scroll, mas
   arrastar, rolar com trackpad e Tab pro próximo card continuam funcionando —
   um carrossel que só anda pelo botão quebra teclado e toque. */
.pjt__track {
  display: flex;
  gap: var(--space-16);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* O card tem foco visível e sombra nenhuma, mas o anel de foco precisa de
     folga pra não ser cortado pelo overflow do scroller. */
  padding-block: var(--space-4);
  margin-block: calc(-1 * var(--space-4));
  scrollbar-width: none;
}
.pjt__track::-webkit-scrollbar {
  display: none;
}
/* Variante "bleed": a trilha ocupa a viewport inteira, sem recortar cards
   na borda esquerda da coluna. O padding mantém o primeiro card e o snap
   alinhados ao título; os anteriores continuam visíveis à esquerda dele. */
[data-proto-carousel="bleed"] .pjt__track {
  margin-inline: calc(50% - 50vw);
  padding-inline: calc(50vw - 50%) var(--space-24);
  /* Percentagens de scroll-padding usam a trilha, não a coluna de main. */
  scroll-padding-inline-start: max(var(--space-24), calc((100vw - var(--space-640)) / 2));
}
/* Variante "column": a trilha respeita a coluna; o excesso só rola. */
[data-proto-carousel="column"] .pjt__track {
  margin-right: 0;
  padding-right: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .pjt__track {
    scroll-behavior: smooth;
  }
}

/* ---------------------------------------------------------------------------
   O card (frame 124:561 / 124:563).
--------------------------------------------------------------------------- */
.pcard {
  flex: 0 0 var(--pcard-w);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  width: var(--pcard-w);
  height: var(--pcard-h);
  padding: var(--space-20);
  border: var(--border-w) solid transparent;
  border-radius: var(--radius-16);
  background: var(--white);
  scroll-snap-align: start;
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: pointer;
  /* `justify-content: space-between` é o que o frame usa: o ar entre a linha
     do ícone, a marca e o texto é sobra dividida, não um gap fixo. Em 332 de
     altura sobram ~66px de cada lado da marca. */
}
/* Hover — o eixo em disputa. `ring` é o que o Figma desenhou (borda --line,
   sem preenchimento); `fill` é a regra que a row `Article` já segue no site
   (só fill --row-hover, sem anel, sem transição — ver docs/figma-workflow.md).
   As duas convivem na mesma página hoje, então dá pra comparar de perto. */
@media (hover: hover) and (pointer: fine) {
  [data-proto-hover="ring"] .pcard:hover {
    border-color: var(--line);
  }
  [data-proto-hover="fill"] .pcard:hover {
    background: var(--row-hover);
  }
}
.pcard:focus-visible {
  outline: var(--border-w) solid var(--ink);
  outline-offset: var(--space-2);
}
/* Linha de cima: só o ícone de expandir, alinhado à direita (frame 133:181).
   Em --faint, não --ink: no frame o SVG exportado vem na cor do modo escuro
   nos dois estados, então a cor virou decisão nossa — o afeto é uma dica, não
   um botão, e some junto com o resto do card no hover. */
.pcard__top {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  width: 100%;
}
.pcard__expand {
  display: block;
  width: var(--space-16);
  height: var(--space-16);
  color: var(--faint);
}
/* A marca do projeto: 64×64, raio 12, borda --line. O frame preenche com
   branco a 5% — que em Dark é o `--ink-a5` do site e em Light desaparece.
   Aqui o fill é `--ink-a5` nos dois modos, que é o token equivalente e se
   comporta igual nos dois (é ink, não white). A imagem, quando existe,
   cobre tudo; quando falha, o elemento sai e sobra o quadrado (regra 4 do
   AGENTS.md). */
.pcard__mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--pcard-mark);
  height: var(--pcard-mark);
  border: var(--border-w) solid var(--line);
  border-radius: var(--radius-12);
  background: var(--ink-a5);
  overflow: hidden;
}
.pcard__mark img {
  display: block;
  flex: none;
  margin: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}
.pcard__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  width: 100%;
}
.pcard__title {
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-base);
  color: var(--ink);
  /* Dois nomes longos ("CloudFaster Academy") cabem em uma linha a 266 −
     40 de padding; um terceiro não caberia, e a altura do card é fixa, então
     o título corta em uma linha e a descrição fica com as duas dela. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pcard__desc {
  line-height: var(--lh-snug);
  color: var(--muted);
  /* Duas linhas no frame. Mais que isso empurraria a marca pra cima e
     quebraria o alinhamento entre cards vizinhos. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   O detalhe do projeto (frame 133:248) — "estilo Vaul do Emil".

   Uma superfície, dois modos. `drawer` sobe de baixo com alça de arrastar e
   escala a página atrás; `modal` centraliza e troca a alça por um botão de
   fechar (uma alça que não arrasta é uma promessa falsa). O conteúdo é o
   mesmo nos dois.

   z-index 54/55: abaixo do lightbox (60/61 em main.css) de propósito — uma
   foto da galeria abre POR CIMA do detalhe, e o Escape do lightbox já roda
   em fase de captura e para ali.
--------------------------------------------------------------------------- */
.pdrawer-wash {
  position: fixed;
  inset: 0;
  z-index: 54;
  /* Igual ao `.cmd-wash` do site, cor e desfoque: `--wash-bg` é o fundo a
     55% e sozinho quase não vela uma página que já é quase branca — quem
     faz a separação é o blur. Com a escala da página atrás, dá o mesmo par
     "scale-and-blur" que o prompt de drawer deste repo descreve
     (prompts.mjs, o kit Sonner/Vaul). */
  background: var(--wash-bg);
  backdrop-filter: blur(var(--glass-blur-lg)) saturate(var(--glass-sat));
  -webkit-backdrop-filter: blur(var(--glass-blur-lg)) saturate(var(--glass-sat));
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-250) var(--ease);
}
.pdrawer-wash[aria-hidden="false"] {
  opacity: 1;
  pointer-events: auto;
}
.pdrawer {
  --pgal-bleed: var(--space-32);
  position: fixed;
  z-index: 55;
  display: flex;
  flex-direction: column;
  width: min(var(--pdrawer-w), calc(100vw - var(--space-48)));
  padding: var(--space-32);
  border-radius: var(--radius-24);
  background: var(--white);
  box-shadow: var(--shadow-modal);
  overflow-y: auto;
  overscroll-behavior: contain;
  pointer-events: none;
  opacity: 0;
}
.pdrawer[aria-hidden="false"] {
  pointer-events: auto;
  opacity: 1;
}

/* --- modo drawer ---------------------------------------------------------
   Ancorado embaixo, encostado na borda inferior: os 24 de raio de baixo
   saem da tela e o que se vê são os de cima, que é o desenho do Vaul. A
   altura para em 92vh pra sempre sobrar um pedaço da página atrás — é o que
   diz "isto é uma camada", sem precisar de texto. */
[data-proto-surface="drawer"] .pdrawer {
  left: 50%;
  bottom: 0;
  max-height: 92vh;
  transform: translate(-50%, 100%);
  transition:
    transform var(--duration-400) var(--ease-out),
    opacity var(--duration-160) var(--ease);
}
[data-proto-surface="drawer"] .pdrawer[aria-hidden="false"] {
  transform: translate(-50%, 0);
}
/* Enquanto o dedo/ponteiro arrasta, quem manda é o JS: a transição sai pra
   que o gesto seja 1:1 com o cursor e possa ser interrompido no meio. */
[data-proto-surface="drawer"] .pdrawer.is-dragging {
  transition: none;
  user-select: none;
}
/* A página atrás encolhe, como no iOS. Em `body > main`, não em `body`: um
   `transform` no body quebraria o `position: fixed` de tudo que está dentro
   dele — inclusive este drawer. */
[data-proto-surface="drawer"] body.pdrawer-open > main {
  transform: scale(0.97);
  transform-origin: 50% 0;
  border-radius: var(--radius-12);
}
[data-proto-surface="drawer"] body > main {
  transition: transform var(--duration-400) var(--ease-out);
}
/* O topbar sai de cena junto, por opacidade. NUNCA por transform: o estado
   escondido dele já é um `translate(-50%, …) scale()` (main.css), e
   sobrescrever a propriedade inteira jogaria a barra pra fora do centro —
   foi o que aconteceu na primeira captura. */
body.pdrawer-open > .topbar {
  opacity: 0;
  pointer-events: none;
}

/* --- modo modal ----------------------------------------------------------
   A geometria do `.cmd-modal` (top/left 50%, scale 0.96 → 1, `--ease-pop`),
   pra que os dois modais do site continuem lendo como uma superfície só —
   a decisão de 15/08/2026 registrada em docs/design-system.md. */
[data-proto-surface="modal"] .pdrawer {
  top: 50%;
  left: 50%;
  max-height: calc(100vh - var(--space-96));
  transform: translate(-50%, -50%) scale(0.96);
  transition:
    transform var(--duration-250) var(--ease-pop),
    opacity var(--duration-200) var(--ease);
}
[data-proto-surface="modal"] .pdrawer[aria-hidden="false"] {
  transform: translate(-50%, -50%) scale(1);
}

/* A alça (frame 133:251): 48×4 em --line, dentro dos 20 de padding do topo.
   Só existe no modo drawer, e é ela que recebe o gesto — daí o alvo de
   toque de 20px de altura em volta de uma barra de 4. */
.pdrawer__grip {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: grab;
  touch-action: none;
}
.pdrawer__grip::before {
  content: "";
  display: block;
  width: var(--space-48);
  height: var(--space-4);
  margin: 0 auto var(--space-12);
  border-radius: var(--radius-full);
  background: var(--line);
}
.pdrawer__grip:active {
  cursor: grabbing;
}
[data-proto-surface="modal"] .pdrawer__grip {
  display: none;
}
[data-proto-surface="drawer"] .pdrawer__close {
  display: none;
}
.pdrawer__close {
  position: absolute;
  top: var(--space-16);
  right: var(--space-16);
  z-index: 1;
}
@media (prefers-reduced-motion: reduce) {
  .pdrawer,
  .pdrawer-wash,
  body > main,
  .topbar {
    transition: none;
  }
}

/* --- conteúdo do detalhe -------------------------------------------------
   Ritmo refinado: 48 depois da capa e 56 entre blocos no desktop;
   no celular, 32 e 40, respectivamente. */
.pdrawer__reveal-pending {
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .pdrawer__reveal-pending { opacity: 1; }
}
.pdrawer__shot,
.pgal__img {
  border: var(--border-w) solid var(--project-image-border);
}
.pdrawer__shot {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-16);
  background: var(--bg);
}
.pdrawer__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-56);
  padding-top: var(--space-48);
}
.pdrawer__head {
  width: 100%;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}
.pdrawer__title {
  text-wrap: balance;
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-base);
  margin: 0;
}
.pdrawer__role {
  color: var(--muted);
  line-height: var(--lh-snug);
  margin: 0;
}
/* Atomic at line breaks, but able to wrap inside an exceptionally long pair
   rather than overflow a narrow column. No fixed widths or inserted breaks. */
.pdrawer__final-words {
  display: inline-block;
  max-inline-size: 100%;
  overflow-wrap: anywhere;
  vertical-align: bottom;
}
.pdrawer__bio {
  color: var(--muted);
  line-height: var(--lh-snug);
  margin: var(--space-24) 0 0;
}
.pdrawer__bio + .pdrawer__bio {
  margin-top: var(--space-16);
}
.pdrawer__section {
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
}
.pdrawer__landings {
  display: flex;
  flex-direction: column;
  gap: var(--space-24);
}
.pdrawer__landings .subproject__name {
  margin-top: 0;
}
/* `.label` de produção já é --faint e, com o flat-type no ar, 16/400 — que é
   exatamente o que o frame pede. Só a margem precisa zerar: a versão do
   `.cmd-modal` traz 32 de topo, e aqui o espaço vem do gap do container. */
.pdrawer .label {
  margin: 0;
}
.pdrawer__items {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}
/* O frame pinta o primeiro item em --ink e os demais em --muted: o primeiro
   "Destaque" é a frase que resume o projeto, o resto é apoio. */
.pdrawer__item {
  color: var(--muted);
  line-height: var(--lh-snug);
  margin: 0;
}
.pdrawer__item:first-child {
  color: var(--ink);
}
.pdrawer__links {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}
.pdrawer__link {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  width: fit-content;
  color: var(--muted);
}
/* O frame usa ícone de 20, contra os 13 do `.fav` de produção. Como a linha
   do link é a única coisa clicável do bloco, o ícone maior ajuda o alvo. */
.pdrawer__link .fav {
  width: var(--space-20);
  height: var(--space-20);
  margin-right: 0;
  border-radius: var(--radius-6);
}
@media (hover: hover) and (pointer: fine) {
  .pdrawer__link:hover {
    color: var(--ink);
  }
}
.pdrawer__link:focus-visible,
.pdrawer__landings .subproject:focus-visible {
  outline: var(--border-w) solid var(--ink);
  outline-offset: var(--space-2);
  border-radius: var(--radius-3);
}

/* --- a galeria -----------------------------------------------------------
   O frame alterna duas meias e uma inteira, repetindo. Em grid de 2 colunas
   isso é só marcar as inteiras com `span 2`; quem decide quais é o JS, que
   também cobre o caso de número ímpar de fotos. As imagens mantêm suas
   molduras uniformes: 16:10 para desktop e 9:19.5 para mobile.
   A fonte completa permanece disponível na ampliação. */
.pgal {
  container-type: inline-size;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-48) var(--space-32);
  align-items: start;
}
.pgal__item {
  display: block;
  padding: 0;
  border: 0;
  border-radius: var(--radius-16);
  background: var(--bg);
  overflow: hidden;
  cursor: zoom-in;
}
.pgal__item--wide {
  grid-column: span 2;
}
.pgal__img {
  border-radius: var(--radius-16);
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: left top;
}
.pgal__item--full .pgal__img {
  aspect-ratio: auto;
}
/* Approved component crops keep their natural height in a masonry group. */
.pgal__masonry {
  grid-column: 1 / -1;
  columns: 3;
  column-gap: var(--space-16);
}
.pgal__masonry > .pgal__item {
  display: block;
  width: 100%;
  break-inside: avoid;
  margin-bottom: var(--space-16);
  background: transparent;
  overflow: visible;
}
.pgal__masonry .pgal__img {
  aspect-ratio: auto;
}
.pgal__banners {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-16);
  align-items: start;
}
.pgal__banners .pgal__img { aspect-ratio: auto; }
.pgal__ticker {
  grid-column: 1 / -1;
  min-width: 0;
  width: calc(100% + var(--pgal-bleed, 0px) * 2);
  margin-inline: calc(-1 * var(--pgal-bleed, 0px));
}
.pgal__ticker-header {
  display: flex;
  align-items: start;
  gap: var(--space-24);
  padding-inline: var(--pgal-bleed, 0px);
  margin-bottom: var(--space-24);
}
.pgal__ticker-header .pgal__caption { margin: 0; flex: 1; }
.pgal__ticker-toggle {
  min-height: var(--space-44);
  padding: var(--space-8) var(--space-16);
  border: 0;
  border-radius: var(--radius-full);
  background: var(--bg);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}
.pgal__ticker-track {
  display: flex;
  gap: var(--space-16);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-behavior: auto;
  overscroll-behavior-x: contain;
  touch-action: pan-x pan-y;
  cursor: grab;
  user-select: none;
}
.pgal__ticker-track::-webkit-scrollbar { display: none; }
.pgal__ticker-track[data-dragging] { cursor: grabbing; }
.pgal__ticker-track > .pgal__item {
  min-width: 0;
  flex: 0 0 auto;
  height: clamp(var(--space-150), 25vw, var(--space-240));
  background: transparent;
  cursor: inherit;
}
.pgal__ticker-track .pgal__img {
  aspect-ratio: auto;
  width: auto;
  max-width: none;
  height: 100%;
  object-fit: contain;
}
.pgal__ticker-track .pgal__item:focus-visible { outline-offset: calc(-1 * var(--space-4)); }
.pgal__banners .pgal__banner-intro {
  grid-column: 1 / -1;
  margin: 0 0 var(--space-8);
}
/* These PNGs already contain their device; keep the transparent perimeter. */
.pgal__item--framed {
  background: transparent;
  overflow: visible;
}
.pgal__item--framed .pgal__img,
.pgal__item--mobile.pgal__item--framed .pgal__img,
.pdrawer__shot--framed {
  border: 0;
  border-radius: 0;
  aspect-ratio: auto;
  background: transparent;
}
@container (max-width: 760px) {
  .pgal__masonry { columns: 2; }
}
@container (max-width: 480px) {
  .pgal__masonry { columns: 1; }
  .pgal__banners { grid-template-columns: minmax(0, 1fr); }
}
.pgal__img--cover {
  object-position: center;
}
.pgal__item:focus-visible {
  outline: var(--border-w) solid var(--ink);
  outline-offset: var(--space-2);
}

/* Mobile: o detalhe ocupa a largura toda e a galeria vira uma coluna. No
   modo drawer isso já é o comportamento nativo do Vaul. */
@media (max-width: 560px) {
  .pdrawer {
    --pgal-bleed: var(--space-20);
    width: 100vw;
    padding: var(--space-20);
    border-radius: var(--radius-24) var(--radius-24) 0 0;
  }
  [data-proto-surface="modal"] .pdrawer {
    width: calc(100vw - var(--space-24));
    border-radius: var(--radius-24);
  }
  .pgal {
    grid-template-columns: minmax(0, 1fr);
  }
  .pgal__item--wide {
    grid-column: span 1;
  }
}

/* Project images retain their own rounded edge when enlarged. */
.lightbox--project {
  border-radius: calc(var(--radius-16) + var(--space-4));
}
.lightbox--project .lightbox__figure {
  border: 0;
  border-radius: var(--radius-16);
}
.lightbox--project .lightbox__img {
  width: auto;
  max-width: 100%;
  height: auto;
  margin-inline: auto;
  border-radius: var(--radius-16);
}

/* Phone captures stay compact; the full source remains available on click. */
.pgal__mobile-row {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-32) var(--space-16);
  align-items: start;
  width: 100%;
  max-width: calc(var(--space-220) * 3 + var(--space-16) * 2);
  margin-inline: auto;
}
.pgal__item--mobile,
.pgal__item--captioned {
  background: transparent;
  overflow: visible;
}
.pgal__item--mobile {
  min-width: 0;
  width: 100%;
}
.pgal__item--mobile .pgal__img {
  width: min(100%, var(--space-220));
  height: auto;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  object-position: top;
  margin-inline: auto;
}
/* Device artwork is vector; the original capture stays separate. These
   percentages map to the SVG viewBoxes, rather than the spacing scale. */
.pgal__item--device {
  background: transparent;
  overflow: visible;
}
.pgal__device {
  position: relative;
  display: block;
  width: 100%;
  isolation: isolate;
}
.pgal__device::after {
  content: "";
  position: absolute;
  inset: 0;
  background: center / 100% 100% no-repeat;
  pointer-events: none;
}
.pgal__screen {
  display: block;
  position: absolute;
  overflow: hidden;
}
.pgal__device .pgal__img {
  width: 100%;
  max-width: none;
  height: 100%;
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
  object-fit: cover;
  object-position: left top;
}
.pgal__device--macbook {
  aspect-ratio: 1200 / 760;
  border-radius: var(--radius-16);
}
.pgal__device--macbook::after {
  background-image: url('/assets/projects/devices/macbook.svg');
}
.pgal__device--macbook .pgal__screen {
  left: 5.833333%;
  top: 3.947368%;
  width: 88.333333%;
  height: 87.171053%;
  border-radius: .754717% / 1.207547%;
}
.pgal__device--iphone {
  aspect-ratio: 9 / 19.5;
  border-radius: 16.923077% / 8.219178%;
}
.pgal__device--iphone::after {
  background-image: url('/assets/projects/devices/iphone.svg');
  background-size: 100% auto;
}
.pgal__device--iphone .pgal__screen {
  left: 4.615385%;
  top: 4.615385%;
  width: 90.769231%;
  height: 90.769231%;
  border-radius: 14.40678% / 6.649283%;
}
.pgal__caption {
  display: block;
  margin-top: var(--space-24);
  color: var(--muted);
  font-size: var(--fs-14);
  line-height: var(--lh-base);
  text-align: start;
  overflow-wrap: anywhere;
  text-wrap: pretty;
}
/* The final wide-image caption shares the centered reading column with
   the case footer. Between image rows, captions use the gallery width. */
.pgal__item--wide > .pgal__caption {
  width: 100%;
  max-width: var(--space-640);
  margin-inline: auto;
}
.pgal__item--wide:not(:last-child) > .pgal__caption {
  max-width: none;
  text-wrap: balance;
}
.pdrawer__decision .label {
  margin: 0;
  font-size: inherit;
  font-weight: var(--fw-medium);
}
@container (max-width: 620px) {
  .pgal__mobile-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-24) var(--space-16);
    max-width: calc(var(--space-420) * 9 / 19.5 * 2 + var(--space-16));
  }
  .pgal__item--mobile .pgal__img {
    max-width: calc(var(--space-420) * 9 / 19.5);
  }
}

.pgal__mobile-row:empty {
  display: none;
}

/* Text has a reading column; images keep the full gallery width. */
.pdrawer__head,
.pdrawer__body > .pdrawer__section {
  width: 100%;
  margin-inline: auto;
  max-width: var(--space-640);
}
@media (max-width: 560px) {
  .pdrawer__body {
    gap: var(--space-40);
    padding-top: var(--space-32);
  }
  .pgal {
    gap: var(--space-32) var(--space-20);
  }
  .pgal__caption {
    margin-top: var(--space-16);
  }
}

.pgal__mobile-captions {
  grid-column: 1 / -1;
  display: grid;
  gap: var(--space-12);
  margin-top: var(--space-n8);
  text-align: start;
}
.pgal__mobile-captions .pgal__caption {
  margin: 0;
}

/* Landing-page links sit beside captions, outside the image button. */
.pgal__landing { min-width: 0; }
.pgal__landing > .pgal__item { width: 100%; }
.pgal__landing-caption { margin-top: var(--space-8); }
.pgal__landing-caption,
.lightbox--project .lightbox__caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-8) var(--space-16);
}
.project-live-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--space-44);
  flex-shrink: 0;
}
