/* ═══════════════════════════════════════════════════════════════════════════
   CONTRATO MOBILE LUNFE · v1.0 — camada de CONTRATO sobre o LUNFE MOBILE ENGINE
   ADITIVA. Carrega DEPOIS de lunfe-tokens.css + lunfe-mobile-engine.css.
   Cada regra declara o GATE que fecha + o número medido (W0-BIS 13/08, prod 390×844).
   Deltas do agente vs. o GOAL literal vêm marcados /* CONTRATO-DELTA */.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── C3 · VIEWPORT E SAFE-AREA — G6 (INDEFINIDO em 14/14) ──
   RAIZ v1.1 (provado 13/08, chromium-1223, prod viva): sob o dc-runtime, o
   :root{} PLANO de topo de um <link> externo NÃO aplica — só blocos @supports
   / @media aplicam (medido: --vh-full=100dvh via @supports e --sticky-bar-h via
   @media RESOLVEM; --safe-* que estavam só no :root plano vinham VAZIOS →
   var(--safe-top,913px)=913px = G6b FAIL, e o calc da reserva colapsava = G8
   FAIL). Correção: entregar --safe-* e --sticky-bar-h pela MESMA via que aplica
   (@supports/@media). Injeção na página real confirmou que @supports{env()}
   resolve p/ 0px. */
@media (max-width: 768px){
  :root{ --vh-full: 100vh; --vh-hero: 88vh; }
}
@supports (height: 100dvh){
  :root{ --vh-full: 100dvh; --vh-hero: 88dvh; }
}
/* safe-area: entregue via @supports (aplica sob o dc-runtime, ao contrário do
   :root plano). env() dentro de custom-property resolve nesta via (provado). */
@supports (padding: env(safe-area-inset-top)){
  :root{
    --safe-top:    env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left:   env(safe-area-inset-left, 0px);
    --safe-right:  env(safe-area-inset-right, 0px);
  }
}
/* fallback da barra sticky de compra: medido 123·131·201 (NÃO 72). O JS
   (lunfe-contrato-mobile.js) mede a barra REAL e sobrescreve --sticky-bar-h na
   body por página; este 140 é só a rede pré-medição. Em @media (aplica sob o
   dc-runtime); os consumidores (C5) usam var(...,140px) inline como 2ª rede. */
@media (max-width: 768px){
  :root{ --sticky-bar-h: 140px; }
}

/* ── C1 · CONTRATO DE RAIL — G3 (1/17 → alvo 17/17) ──
   RAIZ v1.1: os tokens de rail estavam num :root PLANO (não aplica sob o
   dc-runtime) → var(--rail-product) indefinido → o teto max-inline-size dos
   cards não valia → overflow (malhas cards +250px). Movidos p/ @media (aplica). */
@media (max-width: 768px){
  :root{
    --rail-product:   min(88vw, 360px);
    --rail-editorial: min(92vw, 380px);
    --rail-video:     min(84vw, 340px);
    --rail-gap: 12px;
  }
}
@media (max-width: 768px){
  /* sobrescreve o min(72vw,320px) das Leis M3 do engine.
     CONTRATO-DELTA: +max-inline-size p/ CAPAR itens que hoje medem 133–206% vw
     (Malhas 164%/133%, Studio 206%) — a intenção do GOAL "1 dominante" exige teto. */
  [data-lme-slide-fix]{
    min-width: var(--rail-product) !important;
    max-inline-size: var(--rail-product) !important;
  }

  [data-rail],
  [data-carousel-grid],
  [style*="grid-auto-flow:column"],
  [style*="grid-auto-flow: column"]{
    grid-auto-columns: var(--rail-product) !important;
    gap: var(--rail-gap) !important;
    scroll-snap-type: x proximity;
    scroll-padding-inline: 16px;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  [data-rail]::-webkit-scrollbar,
  [data-carousel-grid]::-webkit-scrollbar{ display: none; }

  [data-rail] > *,
  [data-carousel-grid] > *{
    scroll-snap-align: start;
    /* CONTRATO-DELTA: teto no filho de rail — nenhum card domina >88vw */
    max-inline-size: var(--rail-product);
  }

  [data-rail="editorial"], [data-lme-rail="editorial"]{
    grid-auto-columns: var(--rail-editorial) !important;
    scroll-snap-type: x mandatory;
  }
  [data-rail="video"], [data-lme-rail="video"]{
    grid-auto-columns: var(--rail-video) !important;
    scroll-snap-type: x mandatory;
  }
}

/* ── C2 · ALIASES DE UTILITÁRIO — G5 (teste == controle em 14/14) ── */
@media (max-width: 768px){
  [data-shrink]{ min-width: 0; }

  [data-clamp]{
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  [data-clamp="1"]{ -webkit-line-clamp: 1; }
  [data-clamp="2"]{ -webkit-line-clamp: 2; }
  [data-clamp="3"]{ -webkit-line-clamp: 3; }
  [data-clamp=""] { -webkit-line-clamp: 2; }

  [data-truncate]{
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* ── C4 · CONTRATO DE SCROLLER — G1 (afford + limite; stuck→0) ── */
@media (max-width: 768px){
  /* tabela vira o próprio scroller (Studio table +412 → rola no bloco) */
  table{
    display: block;
    max-inline-size: 100%;
    min-inline-size: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }

  /* CONTRATO-DELTA: rede p/ os nós stuck cosméticos (Malhas image-slot/frame +5px):
     mídia e slots nunca ultrapassam a viewport. Seguro (padrão responsivo). */
  img, image-slot, video, picture, [data-ph]{ max-inline-size: 100%; }

  /* afford de borda: sombra que só aparece quando há conteúdo cortado */
  [data-lme-scroll-x], table, [data-rail], [data-carousel-grid]{
    background-image:
      linear-gradient(to right, var(--surface,#fff) 30%, rgb(255 255 255 / 0)),
      linear-gradient(to right, rgb(255 255 255 / 0), var(--surface,#fff) 70%),
      linear-gradient(to right, rgb(0 0 0 / .10), rgb(0 0 0 / 0)),
      linear-gradient(to left,  rgb(0 0 0 / .10), rgb(0 0 0 / 0));
    background-position: 0 0, 100% 0, 0 0, 100% 0;
    background-repeat: no-repeat;
    background-size: 32px 100%, 32px 100%, 12px 100%, 12px 100%;
    background-attachment: local, local, scroll, scroll;
  }

  [data-lme-scroll-x]{ overflow-x: auto !important; }
}

/* ── C7 · ECOSYSTEM BAR — G1 (71–84px) ── */
@media (max-width: 768px){
  [data-screen-label="Ecosystem Bar"], .lunfe-bar{
    scroll-snap-type: x proximity;
    scroll-padding-inline: 14px;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    /* CONTRATO-DELTA: garante que a barra é o scroller (afford do overflow +71/84) */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  [data-screen-label="Ecosystem Bar"]::-webkit-scrollbar{ display: none; }
  [data-screen-label="Ecosystem Bar"] > *{ scroll-snap-align: start; }

  [data-screen-label="Ecosystem Bar"] [aria-current],
  [data-screen-label="Ecosystem Bar"] [data-eco-active]{
    scroll-snap-align: center;
  }

  [data-screen-label="Ecosystem Bar"] > *,
  [data-screen-label="Ecosystem Bar"] button,
  [data-screen-label="Ecosystem Bar"] a{
    min-block-size: var(--tap-min, 44px);
    display: inline-flex;
    align-items: center;
  }
}

/* ── C5 · RESERVA DE STICKY COMMERCE — G8 (N/D → mensurável) ── */
@media (max-width: 768px){
  [data-sticky-bar]{
    inset-block-end: 0 !important;
    padding-block-end: max(8px, var(--safe-bottom, 0px)) !important;
    box-shadow: 0 -1px 0 rgb(0 0 0 / .12);
  }

  /* reserva com FALLBACK DUPLO (var + inline): sobrevive a token indefinido.
     --sticky-bar-h é sobrescrita pelo JS com a altura REAL medida (123/131/201). */
  body:has([data-sticky-bar]),
  body[data-lme-has-sticky]{
    padding-block-end: calc(var(--sticky-bar-h, 140px) + var(--safe-bottom, 0px)) !important;
  }
  /* coexistência com o dock do engine (84px): quando houver os dois, somam */
  body[data-lme-has-float]:has([data-sticky-bar]){
    padding-block-end: calc(var(--sticky-bar-h, 140px) + 84px + var(--safe-bottom, 0px)) !important;
  }

  :target, [id]{ scroll-margin-block-start: calc(var(--header-h, 60px) + 8px); }
}

/* ── C6 · SCROLL-LOCK DECLARATIVO — G7 (2/6 → alvo 6/6) ──
   body[data-lock] é setado pelo lunfe-contrato-mobile.js SÓ com overlay REAL
   cobrindo a viewport E interação recente (detecção estrita + gate de interação).
   CONTRATO-DELTA (decisão medida): o GOAL usava `position:fixed`, que injeta
   CLS (salto do body) — regrediu o G10 em prod 3×. Uso `overflow:hidden` no
   root + `touch-action:none` + `overscroll-behavior:none`: trava o scroll de
   toque real SEM mudar posição → ZERO CLS por construção. Hierarquia 1
   (não regredir G10) > medição por scrollTo sintético da sonda. */
/* RAIZ v1.1 (provado no baseline): estas regras de lock estavam PLANAS no topo
   → o dc-runtime NÃO as aplicava (body[data-lock] era setado pelo JS mas a
   página rolava atrás 461–500px = G7 FAIL "presença≠prova"). Movidas p/ @media
   (via que aplica). Lock no html (scroller do documento) + body; touch-action
   none trava o toque; overscroll-behavior none contém o encadeamento. */
@media (max-width: 768px){
  html:has(body[data-lock]){ overflow: hidden !important; touch-action: none; }
  body[data-lock]{ overflow: hidden !important; overscroll-behavior: none; height: 100dvh; }
  html:has(dialog[open]){ overflow: hidden !important; }

  [data-lme-open], [data-drawer][open], dialog[open]{
    overscroll-behavior: contain;
    max-block-size: min(85dvh, var(--vh-full));
  }
}

/* ── C8 · ANATOMIA DE CARD — G9 (estrutural) ──
   CONTRATO-DELTA: o engine (passSwatches) já normaliza swatch e entrega card
   limpo (medido: 0 elíptico, 0 duplicado). Para NÃO regredir o layout já-bom,
   NÃO forço display:grid no [data-card]; mantenho só o que é seguro e aditivo:
   swatch redondo-na-origem (aspect-ratio:1) e mídia com razão fixa. Se a sonda
   provar que o grid é necessário, promovo. */
@media (max-width: 768px){
  [data-card]{ min-inline-size: 0; }
  [data-card] [data-card-media],
  [data-card] image-slot{ border-radius: 12px; overflow: clip; }

  [data-lme-swatch]{ align-items: center; flex-wrap: nowrap; }
  [data-lme-swatch] > *{
    flex: 0 0 auto;
    aspect-ratio: 1;            /* impede a elipse na origem, não no retrofit */
  }

  [data-card] [data-card-title]{
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    overflow: hidden; min-block-size: 38px;
  }
}

/* ── C10 · COLISÃO DE FLUXO EM LISTA DE DEFINIÇÕES — G2 (PDP) ── */
@media (max-width: 768px){
  dl, [data-spec-list], [data-resumo]{
    display: grid;
    grid-template-columns: 1fr;
    row-gap: 12px;
    align-items: start;
  }
  dl > dt, [data-spec-list] > :nth-child(odd){
    block-size: auto !important; min-block-size: 0 !important;
    align-self: start;
  }
  dl > dd, [data-spec-list] > :nth-child(even){
    block-size: auto !important; min-block-size: 0 !important;
    margin-inline-start: 0;
  }
  [data-lme-autoh], [data-spec-row]{
    block-size: auto !important; min-block-size: 0 !important;
  }
}

/* ── C9 · CONTRATO DE MÍDIA — G11 (srcset ausente 6/6; oversize) ──
   CSS não corrige srcset (bytes na rede) — reserva geometria e impede distorção.
   AÇÃO FORA DAQUI: srcset/sizes na origem. */
@media (max-width: 768px){
  image-slot, [data-img-a], [data-img-b], [role="img"]{
    display: block;
    inline-size: 100%;
    background-size: cover;
    background-position: center;
  }
  img[width][height]{ block-size: auto; }
  /* CONTRATO-DELTA: linha attr(data-ar type(<number>),1) do GOAL REMOVIDA —
     attr() tipado não é confiável no Chromium/Safari alvo e distorceria imagens
     sem data-ar. Geometria preservada por img[width][height] acima. */
}

/* ── C11 · MOVIMENTO E ACESSIBILIDADE ── */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  [data-rail], [data-carousel-grid]{ scroll-snap-type: none; }
}
/* ── C12 · GOVERNANÇA data-mobile (R6) — ARRANJO declarado pela seção ──
   O Claude Design taggeia a <section data-mobile="stack|rail|accordion|hide">;
   o contrato governa o arranjo mobile SEM adivinhar (fecha a lacuna FASE 2 do
   BRIEF COMPOSIÇÃO). TUDO em @media (aplica sob o dc-runtime; regra plana morre —
   Lição 5). OPT-IN: só afeta seções marcadas → zero risco ao conteúdo não-taggeado.
   Estrutura real do export: <section> → <div data-om-col style="grid-template-columns:..">. */
@media (max-width: 768px){
  /* hide — seção removida no mobile (ex.: UGC com placeholders vazios) */
  [data-mobile="hide"]{ display: none !important; }

  /* stack — grade multi-coluna da seção colapsa p/ 1 coluna, fluxo vertical.
     Mira o container de grid interno (inline grid-template-columns / data-om-col /
     grid-auto-flow:column) e vira flex-row em coluna. (R1) */
  [data-mobile="stack"] [data-om-col],
  [data-mobile="stack"] [data-om-two],
  [data-mobile="stack"] [style*="grid-template-columns"],
  [data-mobile="stack"] [style*="grid-auto-flow:column"],
  [data-mobile="stack"] [style*="grid-auto-flow: column"]{
    display: block !important;
    grid-template-columns: 1fr !important;
  }
  [data-mobile="stack"] [style*="display:flex"]:not([data-keep-row]){ flex-direction: column !important; }

  /* rail — o container de grid da seção vira TRILHO horizontal 1-dominante com snap
     (devolve ~60% de altura vs empilhar 3+ itens). (R2) */
  [data-mobile="rail"] [data-om-col],
  [data-mobile="rail"] [style*="grid-template-columns"]{
    display: grid !important;
    grid-auto-flow: column !important;
    grid-auto-columns: var(--rail-product) !important;
    grid-template-columns: none !important;
    gap: var(--rail-gap) !important;
    overflow-x: auto !important;
    scroll-snap-type: x proximity;
    scroll-padding-inline: 16px;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  [data-mobile="rail"] [data-om-col] > *,
  [data-mobile="rail"] [style*="grid-template-columns"] > *{ scroll-snap-align: start; }
  [data-mobile="rail"] ::-webkit-scrollbar{ display: none; }

  /* accordion — itens colapsáveis (FAQ, glossário, comparador, ficha). O JS wira o
     toggle; aqui o estado visual. Convenção: [data-acc-item] > [data-acc-head]
     (clicável) + [data-acc-body]. O JS monta a convenção via heurística se faltar. (R5) */
  [data-mobile="accordion"]{ display: block !important; }
  [data-mobile="accordion"] [data-acc-item]{ border-block-end: 1px solid var(--hairline, #ECECEC); }
  [data-mobile="accordion"] [data-acc-head]{
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; min-block-size: var(--tap-min, 44px); cursor: pointer; padding-block: 12px;
  }
  [data-mobile="accordion"] [data-acc-head]::after{ content: "+"; font-size: 20px; line-height: 1; opacity: .5; flex: 0 0 auto; }
  [data-mobile="accordion"] [data-acc-item][data-acc-open] [data-acc-head]::after{ content: "\2013"; }
  [data-mobile="accordion"] [data-acc-item]:not([data-acc-open]) [data-acc-body]{ display: none !important; }

  /* qualquer seção governada respeita fluxo: mata altura fixa em texto dinâmico */
  [data-mobile] [data-lme-autoh], [data-mobile] [data-spec-row]{ block-size: auto !important; min-block-size: 0 !important; }

  :focus-visible{ outline: 2px solid currentColor; outline-offset: 2px; }
}

/* ── C13 · TAP TARGET DE LINK DE CONTATO — G(I6) (trocas 1/7 <44 → alvo 0/7) ──
   O meta-header do Portal de Trocas traz o link WhatsApp com min-height:36px
   INLINE (medido w177×h36 em 360/390/430 → I6.samplesBad). Regra plana morre sob
   o dc-runtime (Lição 5) → @media; inline vence stylesheet → !important. Eleva
   qualquer link wa.me ao piso de toque 44px (R5.5). Físico (min-height) p/ casar e
   vencer o inline exato, sem ambiguidade de alias block-size. Só aumenta a altura
   do alvo (nunca regride layout: header usa flex-wrap; +8px por linha, trivial). */
@media (max-width: 768px){
  a[href^="https://wa.me/"]{
    min-height: var(--tap-min, 44px) !important;
    display: inline-flex;
    align-items: center;
  }
}
