/* ==========================================================
   Ideals — Estilo base
   Site é tema escuro fixo — não existe mais alternância de tema
   (o toggle claro/escuro foi removido a pedido do Wendell, 01/09).
   ========================================================== */
:root {
  --orange: #FF6A00;
  --orange-dark: #E25400;
  --charcoal: #111111;
  --font: 'Poppins', system-ui, -apple-system, sans-serif;
  --radius: 14px;
  --container: 1160px;

  /* tema escuro (padrão) */
  --bg: #131316;
  --surface: #1a1a1a;
  --surface-2: #232323;
  --border: rgba(255,255,255,.09);
  --text: #ffffff;
  --text-muted: rgba(255,255,255,.65);
  --bg-dot: rgba(255,255,255,.07);
  color-scheme: dark;
}

* { box-sizing: border-box; }
/* Touch browsers paint their own default tap-highlight (a flat blue
   tint) on ANY tappable element, not just the ones already fixed one
   at a time (.review-card had this same complaint earlier — "quando
   clico marca em azul, não quero isso" — then it turned up again on
   the service cards). Reset it globally instead of chasing it element
   by element every time a new tappable thing gets built. */
* { -webkit-tap-highlight-color: transparent; }
/* background matches body's own so the mobile browser's overscroll
   bounce (dragging past the top/bottom) doesn't flash the browser's
   own default canvas color instead of the site's dark theme ("quando
   eu começo a arrastar pra baixo, aparece um fundo preto... depois
   some, mas mesmo assim está incomodando"). overscroll-behavior-y
   stops the bounce itself where supported; the background is the
   fallback for wherever it isn't. */
html {
  scroll-behavior: smooth;
  overflow-x: hidden;
  background: var(--bg);
  overscroll-behavior-y: none;
}

/* body is deliberately transparent — the page's dark ground comes from
   `html` above, and body must NOT repaint it. .bg-fx is a z-index:-1
   child of body: in paint order that puts it above the canvas (html's
   background) but below body's own background box, so an opaque body
   background covers the whole ambient layer — every glow, dot and the
   grain — leaving a flat black page. That is exactly what happened when
   `html` got its background for the mobile overscroll-bounce fix: until
   then html was bare, body's background propagated to the canvas
   instead of painting as a normal block, and .bg-fx showed through. The
   propagation stopped the moment html had its own background, and the
   whole ambient layer went invisible site-wide — which is what was
   behind "o fundo ainda está preto apenas, quero os detalhes" (measured
   with Playwright: forcing body transparent took a sample patch from
   stdDev 1.7 to 8.5). Keep html painting the ground, keep body clear. */
body {
  margin: 0;
  overflow-x: hidden;
  font-family: var(--font);
  color: var(--text);
  background: transparent;
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  transition: background-color .25s ease, color .25s ease;
}

.site-loader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: grid;
  place-items: center;
  background: #0a0b0d;
  transition: opacity .8s ease, visibility .8s ease;
}

.site-loader.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.loader-mark {
  width: min(28vw, 220px);
  position: relative;
  display: grid;
  place-items: center;
  transform-origin: center center;
  transform: translate(0, 0) scale(1);
  transition: transform .9s cubic-bezier(.22, 1, .36, 1), opacity .7s ease;
}

.site-loader.is-moving .loader-mark {
  transform: translate(var(--loader-move-x), var(--loader-move-y)) scale(var(--loader-scale));
}

.loader-mark img {
  display: block;
  width: 100%;
  height: auto;
  transform: scale(1.002);
  clip-path: inset(0 0 0 0 round 0px);
  -webkit-mask-image: linear-gradient(to right, #000 0%, #000 100%);
  mask-image: linear-gradient(to right, #000 0%, #000 100%);
  animation: write-logo 1.8s cubic-bezier(.22, 1, .36, 1) forwards;
  filter: brightness(0.98);
}

@keyframes write-logo {
  0% {
    clip-path: inset(0 100% 0 0 round 0px);
    opacity: 0.2;
    transform: scale(1.01);
  }
  30% {
    opacity: 1;
  }
  100% {
    clip-path: inset(0 0 0 0 round 0px);
    opacity: 1;
    transform: scale(1);
  }
}

/* Whole-site ambient background: sits behind absolutely everything as a
   fixed, negative-z-index layer so it never scrolls and never gets
   re-painted per section. This only works because `section`/.site-footer
   are transparent (see below) — a fixed z-index:-1 element still paints
   behind normal in-flow siblings in stacking order, so if those siblings
   kept their own opaque `background: var(--bg)` this would be invisible
   everywhere except the gaps between sections.
   The cursor-following glow (.bg-fx-spot) was removed 31/08 per request
   ("tira o efeito de luz que segue o cursor e afins") — that was
   specifically about the pointer-tracking behavior, not ambient light
   in general. 01/09: static glow spots added back ("quero alguns pontos
   de iluminação... pra dar uma diversificada") — fixed positions, no
   JS, nothing tracks the cursor. Four soft radial-gradients (three
   orange at different opacities/sizes so they don't read as identical
   copies, one subtle purple for variety without fighting the brand
   color) sit behind the dot grid, which stays the last/bottom layer so
   the dots are still visible on top of the glows.
   05/09: turned up across the board — "o fundo ainda está preto
   apenas, quero os detalhes". At the original values (dots at 6%
   opacity, glows topping out at 14%) the whole layer was essentially
   imperceptible against the photo-heavy hero and the cards' own opaque
   surfaces, reading as flat black exactly like the complaint. Glow
   opacities roughly doubled and spread wider (softer, bigger blooms
   instead of tight spots), --bg-dot went from .06 to .14, and a second,
   coarser dot layer was added on top of the fine grid — two different
   scales read more like a scattered starfield (fits the rocket/space
   brand) than one uniform sheet of graph paper.
   05/09: added a film-grain texture on top ("preciso que adicione
   alguma textura no background de todo o site") — a tiny SVG
   feTurbulence tile (fractalNoise, stitched so it repeats with no
   visible seam) baked to a very low, mostly-white alpha via
   feColorMatrix, tiled at 140px and painted as the topmost layer so it
   sits uniformly over the glows/dots/page content alike, everywhere
   .bg-fx reaches (every page includes it, so this covers the whole
   site from one place). No JS/canvas needed, no extra request either
   — it's inline as a data: URI. */
.bg-fx {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"),
    radial-gradient(circle at 12% 18%, rgba(255,106,0,.15), transparent 46%),
    radial-gradient(circle at 88% 12%, rgba(155,95,255,.10), transparent 42%),
    radial-gradient(circle at 92% 78%, rgba(255,106,0,.12), transparent 48%),
    radial-gradient(circle at 20% 92%, rgba(255,106,0,.09), transparent 44%),
    radial-gradient(rgba(255,255,255,.20) 1.5px, transparent 2.6px),
    radial-gradient(var(--bg-dot) 1px, transparent 1.6px);
  background-size: 140px 140px, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 168px 184px, 34px 34px;
  background-repeat: repeat, no-repeat, no-repeat, no-repeat, no-repeat, repeat, repeat;
}

img, svg { display: block; max-width: 100%; }

a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
  font-weight: 800;
  line-height: 1.15;
  margin: 0 0 .5em;
  letter-spacing: -0.01em;
}

p { margin: 0 0 1em; color: var(--text-muted); }

.text-orange { color: var(--orange); }

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 clamp(18px, 2.8vw, 24px);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--orange);
  color: #fff;
  padding: 12px 20px;
  z-index: 1000;
  border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 14px 26px;
  /* Was a full pill (999px) — the only element on the site shaped that
     way, while cards/modal/icons all use a moderate 14-20px radius
     ("manter os botões menos arredondados?"). 18px ties it back into
     that same system without losing the "clearly a button" read a pill
     gives; matches .mobile-cta-button's own 18px below, which had
     already landed on the same value independently. */
  border-radius: 18px;
  font-weight: 600;
  font-size: 0.95rem;
  white-space: nowrap;
  transition: transform .18s ease, box-shadow .18s ease, background .18s ease, color .18s ease, border-color .18s ease;
  border: 2px solid transparent;
}
.btn-primary {
  background: var(--orange);
  color: #fff;
  box-shadow: 0 8px 20px rgba(255,106,0,.28);
}
.btn-primary:hover { background: var(--orange-dark); transform: translateY(-2px); box-shadow: 0 12px 24px rgba(255,106,0,.35); }
/* Metallic band added to the flat 2-stop gradient ("essa cor verde
   pode ter um detalhe de luz metalizado") — same idea as the hero
   kicker's metallic text (dark green -> bright near-white band ->
   dark green), just as a background instead of a text-clip. Started
   static, then "esse efeito pode passear pelo botão também" — same
   sweep as .hero-kicker, reusing the same @keyframes kicker-shine
   (it's generic, just drives background-position, not tied to any
   one gradient's colors). background-size has to be repeated inside
   :hover too: the `background` shorthand resets ALL background-*
   sub-properties to initial (including background-size) whenever it's
   used, even for ones it doesn't mention — without redeclaring it
   there, hovering would snap the gradient back to 100% and cancel the
   sweep's room to move. */
.btn-whatsapp {
  background: linear-gradient(155deg, #159149 0%, #34e07a 22%, #8dffc4 42%, #34e07a 62%, #1fae52 100%);
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0,0,0,.4);
  box-shadow: 0 10px 24px rgba(37,211,102,.4), inset 0 1px 0 rgba(255,255,255,.25);
}
.btn-whatsapp:hover {
  background: linear-gradient(155deg, #1aa354, #3dfb8c 22%, #a8ffd8 42%, #3dfb8c 62%, #22c25d 100%);
  background-size: 300% 100%;
  transform: translateY(-2px);
  box-shadow: 0 14px 28px rgba(37,211,102,.5), inset 0 1px 0 rgba(255,255,255,.3);
}
.btn-outline {
  background: transparent;
  color: var(--text);
  border-color: var(--border);
}
.btn-outline:hover { background: var(--text); color: var(--bg); border-color: var(--text); transform: translateY(-2px); }
.btn-solid-dark { background: var(--surface); color: var(--text); border-color: var(--border); font-weight: 300; }
.btn-solid-dark:hover { background: var(--surface-2); transform: translateY(-2px); }
.btn-lg { padding: 18px 34px; font-size: 1.05rem; }

/* ==========================================================
   Header
   ========================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 500;
  background: transparent;
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 78px;
  gap: 20px;
  max-width: none;
  padding-left: clamp(32px, 8vw, 130px);
  padding-right: clamp(32px, 8vw, 130px);
}
.logo {
  display: inline-flex;
  align-items: center;
  transition: transform .3s ease, opacity .3s ease;
}
/* Logo hides upward on scroll, nav/actions stay put — .logo keeps its
   flex-row space (opacity+transform, not display:none), so the nav
   links don't shift left when it disappears. */
.site-header.is-scrolled .logo {
  transform: translateY(-60px);
  opacity: 0;
  pointer-events: none;
}
.logo img { height: 40px; width: auto; display: block; }
.dot { color: var(--orange); }

.main-nav {
  display: flex;
  gap: 32px;
  align-items: center;
  margin-left: auto;
}
.main-nav a {
  font-weight: 300;
  font-size: 0.82rem;
  color: var(--text-muted);
  position: relative;
  padding: 4px 0;
  transition: color .18s ease;
}
.main-nav a:hover { color: var(--text); }
.main-nav a::after {
  content: '';
  position: absolute;
  left: 0; bottom: -2px;
  width: 0; height: 2px;
  background: var(--orange);
  transition: width .2s ease;
}
.main-nav a:hover::after { width: 100%; }

/* --- Submenu de Serviços -------------------------------------------- */
/* "Serviços" continua levando pra seção da home; o mouse (ou o foco pelo
   teclado) abre a lista das páginas de cada serviço. Cada nome no
   metalizado da sua cor — a mesma paleta por serviço dos cards da home.
   "Site Profissional" está de fora de propósito: ainda não tem página, e
   item de menu que dá 404 é pior que item ausente. */
.nav-drop { position: relative; display: flex; align-items: center; }
.nav-drop-alvo { display: inline-flex; align-items: center; }
.nav-drop-seta {
  width: 5px;
  height: 5px;
  margin-left: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform .2s ease;
}
/* A seta vira quando o menu abre — e ele abre de três jeitos: mouse
   (hover), teclado (focus-within) e toque (a classe is-aberto, posta
   pelo main.js). O :hover fica isolado num @media próprio porque em
   tela de toque ele não existe, e o que sobra tem que continuar
   valendo. */
.nav-drop:focus-within .nav-drop-seta,
.nav-drop.is-aberto .nav-drop-seta { transform: translateY(1px) rotate(225deg); }
@media (hover: hover) and (pointer: fine) {
  .nav-drop:hover .nav-drop-seta { transform: translateY(1px) rotate(225deg); }
}

.nav-drop-menu {
  position: absolute;
  top: calc(100% + 16px);
  left: 50%;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 216px;
  padding: 8px;
  border-radius: 14px;
  border: 1px solid rgba(255,255,255,.12);
  background: rgba(20,18,26,.97);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 20px 44px rgba(0,0,0,.5);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -6px);
  transition: opacity .18s ease, transform .18s ease, visibility .18s ease;
}
/* A ponte. Entre o link e o menu existem 16px de vão; sem uma área
   invisível cobrindo esse vão, o ponteiro sai do :hover no meio do
   caminho e o menu fecha antes de a pessoa chegar nele. */
.nav-drop-menu::before {
  content: '';
  position: absolute;
  left: 0; right: 0;
  top: -20px;
  height: 20px;
}
/* Abrir o menu. Em tela de toque não existe passar o mouse, então o
   hover NÃO pode ser a única porta: quem abre ali é a classe is-aberto,
   posta no toque pelo main.js. O teclado entra pelo focus-within. */
.nav-drop:focus-within .nav-drop-menu,
.nav-drop.is-aberto .nav-drop-menu {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}
@media (hover: hover) and (pointer: fine) {
  .nav-drop:hover .nav-drop-menu,
  .nav-drop-menu:hover {
    opacity: 1;
    visibility: visible;
    transform: translate(-50%, 0);
  }
}

.main-nav .nav-servico {
  padding: 9px 12px;
  border-radius: 9px;
  font-size: .8rem;
  font-weight: 700;
  white-space: nowrap;
  transition: background-color .18s ease;
}
.main-nav .nav-servico::after { display: none; }
.main-nav .nav-servico:focus-visible { background: rgba(255,255,255,.08); outline: none; }
@media (hover: hover) and (pointer: fine) {
  .main-nav .nav-servico:hover { background: rgba(255,255,255,.08); }
}
.main-nav .nav-servico.is-atual { background: rgba(255,255,255,.06); }

/* O metalizado, um por cor. As rampas aqui são mais claras que as dos
   títulos: num nome pequeno sobre fundo escuro, a rampa de título
   (que fecha quase no preto nas pontas) deixaria as pontas ilegíveis.
   background-image separado de background-size de propósito: o
   atalho `background` zera background-size e mata a animação. */
.nav-servico span {
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
.nav-servico--laranja span {
  background-image: linear-gradient(95deg, #ff7a24 0%, #ffa661 20%, #ffdcc0 42%, #ffffff 52%, #ffdcc0 62%, #ffa661 82%, #ff7a24 100%);
}
.nav-servico--roxo span {
  background-image: linear-gradient(95deg, #8b63d6 0%, #b48cff 20%, #ddccff 42%, #ffffff 52%, #ddccff 62%, #b48cff 82%, #8b63d6 100%);
}
.nav-servico--amarelo span {
  background-image: linear-gradient(95deg, #d9a136 0%, #f5c65c 20%, #ffe9b8 42%, #ffffff 52%, #ffe9b8 62%, #f5c65c 82%, #d9a136 100%);
}
.nav-servico--verde span {
  background-image: linear-gradient(95deg, #1faf57 0%, #45d685 20%, #b6f5cf 42%, #ffffff 52%, #b6f5cf 62%, #45d685 82%, #1faf57 100%);
}
.nav-servico--azul span {
  background-image: linear-gradient(95deg, #3f7fdc 0%, #6fa4ff 20%, #c3daff 42%, #ffffff 52%, #c3daff 62%, #6fa4ff 82%, #3f7fdc 100%);
}
@media (prefers-reduced-motion: reduce) {
  .nav-servico span { animation: none; }
}

.header-actions { display: flex; align-items: center; gap: 14px; margin-left: 12px; }

.menu-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
}
.menu-toggle span {
  width: 24px; height: 2px;
  background: var(--text);
  border-radius: 2px;
  transition: transform .2s ease, opacity .2s ease;
}

/* ==========================================================
   Hero
   ========================================================== */
.hero {
  position: relative;
  background: transparent;
  color: var(--text);
  /* overflow: visible (v3 of the earth, 30/08) — tried overflow:hidden
     to contain the earth strictly inside .hero, but that put a hard
     straight cut across the sphere right at the hero/services seam,
     which read as broken, not intentional. The Wendell confirmed: he
     wants it to keep going — "não quero que ela corte, quero que ela
     continue... complete a imagem da terra" — into the top of
     .services as you scroll, same idea as the very first version of
     this feature. See .services .container below for how the cards
     stay legible on top of that bleed. */
  overflow: visible;
  min-height: calc(100vh - 78px);
  padding: 90px 0 100px;
}
/* Earth graphic: enormous, anchored to the hero's own bottom-right
   corner and pushed further off-screen with negative right/bottom so
   only its upper-left arc is ever visible, docked below the rocket to
   read as "the rocket just launched off of this". A real PNG (not a
   CSS-drawn shape) — don't redesign it in CSS, only reposition/resize
   the element around it. z-index:1 keeps it behind both the rocket
   (.hero-emblem, z-index:2) and the hero copy (text/buttons are in
   normal flow, painting after this positioned element regardless).
   right/bottom pushed further than a naive "60-75% off-screen" reading
   would suggest — pulled in tighter and the visible arc is deliberately
   kept clear of the rocket's own flame/smoke (which are semi-transparent
   in rocket.png, so they'd blend into the earth's bright, busy surface
   and visually vanish if the two overlapped there — confirmed by
   screenshot, not by z-index, since z-index was already correct).

   Still split into two elements (.hero-earth for position/size,
   .hero-earth-img below for the image itself) even though the image
   is static now — the scroll-driven rotation this split existed for
   was removed 02/09 ("tira a animação... deixa estática mesmo"). No
   functional reason to re-merge them, so left as-is. */
.hero-earth {
  position: absolute;
  right: clamp(-680px, -34vw, -380px);
  bottom: clamp(-620px, -32vw, -340px);
  width: clamp(750px, 66vw, 1100px);
  z-index: 1;
  pointer-events: none;
  /* drop-shadow lives HERE, not on the rotating .hero-earth-img below —
     filter is one of the most expensive things a browser recomputes,
     and putting it on the element whose transform changes every
     animation frame (during/after scroll) made the whole page janky.
     The earth is a circle, so the glow's silhouette barely changes as
     it spins — no visible difference moving it up a level, only a
     real performance win. */
  filter:
    drop-shadow(0 0 24px rgba(255, 106, 0, .18))
    drop-shadow(0 0 70px rgba(255, 106, 0, .08));
  /* Even moved off the rotating element, this is still a huge (up to
     1100px) filtered image sitting in normal scroll flow — without a
     compositing hint the browser can end up re-rasterizing the blurred
     drop-shadow as it scrolls past, which reads as general scroll jank,
     not just jank tied to the rotation. will-change:transform (even
     though nothing here actually transforms) pins it to its own GPU
     layer instead, so scrolling just recomposites a cached texture. */
  will-change: transform;
}
/* Static now (02/09) — used to rotate with scroll via main.js, removed
   per request ("deixa estática mesmo"). No transform/animation left. */
.hero-earth-img {
  width: 100%;
  height: auto;
  display: block;
  user-select: none;
}
.hero-inner {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  align-items: center;
  gap: 48px;
  max-width: none;
  padding-left: clamp(24px, 8vw, 130px);
  padding-right: clamp(24px, 8vw, 130px);
}
/* Grid items default to min-width:auto, which refuses to shrink a track
   below its content's own min-content size. .hero-visual's child
   (.hero-emblem, width:min(680px,92vw)) is wider than the available
   column on narrow phones, so without this the grid column itself was
   forced wider to fit it — dragging .hero-copy's whole column (and
   everything centered inside it: headline, tagline+divider, buttons)
   ~30px off-center to the right along with it. Found by comparing
   getBoundingClientRect() of the headline against window.innerWidth via
   CDP — a screenshot alone didn't explain the consistent offset seen
   across three unrelated centering mechanisms (text-align, inline-block,
   flexbox). min-width:0 lets the column shrink to the padded content
   width again; .hero-emblem can still overflow its own box exactly like
   .hero-earth already does, that's unaffected. */
.hero-copy, .hero-visual { min-width: 0; }
/* Stats strip capping the hero — same full-bleed padding as .hero-inner
   (not the generic centered .container) so its left edge lines up with
   the headline above it. A plain top rule + flex row, no vertical
   dividers between the numbers (asked for explicitly) — just gap. */
.hero-stats {
  position: relative;
  z-index: 2;
  max-width: none;
  padding-left: clamp(24px, 8vw, 130px);
  padding-right: clamp(24px, 8vw, 130px);
  /* Desktop had the stat cards sitting right under the hero CTA
     buttons with barely any air between them ("estão muito colados nos
     botoes de CTA e tem espaço para descer") — scales up with viewport
     width like the padding above, floored back to the original 14px on
     mobile below so the stacked mobile layout is untouched. */
  margin-top: clamp(24px, 4vw, 56px);
  display: flex;
  flex-wrap: wrap;
  gap: 40px 64px;
}
/* Each stat is its own card (same idea as .service-card: a contained
   surface instead of bare text floating over the Earth image) but
   translucent + blurred rather than a flat opaque --surface block —
   a solid rectangle read as too harsh/abrupt against the Earth's own
   glow behind it ("os quadrados estão muito brutos"). The frosted-
   glass look lets that glow bleed through softly instead of the card
   looking pasted on top. Center of each card also carries the site's
   own visual language in miniature ("preciso que o centro de cada um
   desses retangulos tenham alguma coisa pra ambientar mais eles no
   site em si") — a soft centered orange glow (echoes the ambient
   .bg-fx glow spots and the rocket/Earth glow) plus a fine dot-grid
   texture (echoes .bg-fx's own dot pattern, just denser/smaller-scale
   since the card itself is small) instead of flat empty space around
   the text. */
.hero-stats-item {
  display: flex;
  flex-direction: column;
  gap: 6px;
  position: relative;
  overflow: hidden; /* clips the ::after shine streak to the card's
    own rounded corners instead of spilling past them */
  background-color: rgba(26, 26, 26, .55);
  background-image:
    radial-gradient(circle at 50% 45%, rgba(255,106,0,.18), transparent 65%),
    radial-gradient(rgba(255,255,255,.07) 1px, transparent 1.6px);
  background-size: auto, 18px 18px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: var(--radius);
  padding: 20px 26px;
  box-shadow: 0 14px 30px rgba(0,0,0,.3);
  transition: transform .3s ease, box-shadow .3s ease, border-color .3s ease;
}
.hero-stats-item:hover {
  transform: scale(1.04);
  border-color: rgba(255, 106, 0, .4);
  box-shadow: 0 20px 40px rgba(0,0,0,.35), 0 0 30px 4px rgba(255,106,0,.14);
}
/* Metallic shine sweep — a diagonal light band that crosses the card
   once per hover (not a running loop like .hero-kicker/.btn-whatsapp's
   shine: the animation is only declared inside :hover, so it restarts
   fresh every time the pointer arrives instead of playing constantly
   in the background). ::after instead of a background layer so it
   composites over the existing radial-gradient/dot-grid backgrounds
   without needing to touch that background-image list. */
.hero-stats-item::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 42%, rgba(255,255,255,.4) 50%, transparent 58%);
  background-size: 250% 100%;
  background-position: 150% 0;
  pointer-events: none;
}
.hero-stats-item:hover::after {
  animation: stats-shine .9s ease forwards;
}
@keyframes stats-shine {
  from { background-position: 150% 0; }
  to   { background-position: -50% 0; }
}
.hero-stats-number {
  font-size: clamp(1.9rem, 5.2vw, 2.4rem);
  font-weight: 800;
  color: var(--orange);
  line-height: 1;
}
.hero-stats-label {
  font-size: 0.85rem;
  color: var(--text-muted);
  max-width: 200px;
}
.eyebrow {
  color: var(--text);
  font-weight: 700;
  font-size: clamp(2.1rem, 4.6vw, 3.6rem);
  text-transform: uppercase;
  letter-spacing: .02em;
  margin-bottom: 20px;
  line-height: 1.15;
}
.eyebrow .word-swap,
.eyebrow .word-swap-item {
  color: var(--orange);
}
.eyebrow-line2 {
  display: inline-block;
  font-size: 1.35em;
}
/* Metallic-green gradient text: a symmetric bright band (near-white)
   fading to darker green on both edges, clipped to the glyph shapes.
   -webkit-text-fill-color is needed alongside color:transparent for
   Safari/WebKit specifically — background-clip:text alone doesn't hide
   the fill there. Shine now animates across the 3 words ("preciso que
   adicione uma animação para que ela 'passeie' pelas 3 palavras",
   01/09) — was deliberately static before (a performance pass had
   just wrapped up when this was first built), but that's a direct,
   explicit request now, overriding that earlier caution. background-size
   is 3x the element's own width so there's room for the bright band to
   travel; animating background-position-x from 0% to 100% sweeps it
   left to right. Loop resets are inaudible/invisible because both
   gradient ends are the same dark green (#0e5c34), so the jump back to
   0% at each cycle lands on a color that already matches what's there. */
/* Hero search (02/09) — filters the .service-card grid below by
   keyword overlap (see main.js). First element in .hero-copy, above
   even the kicker, so it reads as the page's opening question rather
   than a secondary tool. */
.hero-search {
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 480px;
  margin: 0 0 26px;
  padding: 4px 4px 4px 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  transition: border-color .25s ease, box-shadow .25s ease;
}
/* Desktop hides the homepage's search bar for now (still shows on
   /landing-pages/, which uses .lp-hero-copy, not .hero-copy, so this
   extra-specific selector doesn't touch it) — request was "not on PC
   yet, just mobile". Re-shown inside the same max-width:960px query
   .hero-search already uses for its own mobile centering below. */
.hero-copy .hero-search { display: none; }
.hero-search:focus-within {
  border-color: var(--orange);
  box-shadow: 0 0 0 4px rgba(255, 106, 0, .14);
}
.hero-search-icon { flex-shrink: 0; width: 18px; height: 18px; color: var(--text-muted); }
.hero-search-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  outline: none;
  color: var(--text);
  font-family: inherit;
  font-size: 0.95rem;
  padding: 12px 0;
}
/* Placeholder mais apagado que o texto digitado — ele é dica, não
   conteúdo. --text-muted (65%) competia demais com o valor real. */
.hero-search-input::placeholder { color: rgba(255,255,255,.38); }
.hero-search-count {
  flex-shrink: 0;
  font-size: 0.72rem;
  color: var(--text-muted);
  padding-right: 14px;
  white-space: nowrap;
}
/* Small caption directly under the search box (currently only used on
   /landing-pages/) — margin-top pulls it close to .hero-search instead
   of using the default paragraph spacing, so it reads as a label for
   the field above it rather than a new paragraph. */
.hero-search-hint {
  margin: -14px 0 22px;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.hero-kicker {
  margin: 0 0 10px;
  display: block;
  font-size: clamp(1.1rem, 2vw, 1.4rem);
  font-weight: 700;
  letter-spacing: .01em;
  text-transform: uppercase;
  /* Width is set inline by main.js to match .eyebrow-line1's rendered
     width; text-align-last is what actually does the stretching (it
     targets the last/only line of a block, spreading word-spacing to
     fill it) — text-align:justify alone has nothing to justify with
     just one line, text-align-last is the piece that matters here. */
  text-align: justify;
  text-align-last: justify;
  background: linear-gradient(95deg, #0e5c34 0%, #1fae52 18%, #6dffb0 40%, #eafff2 50%, #6dffb0 60%, #1fae52 82%, #0e5c34 100%);
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 0 18px rgba(52,224,122,.35);
}
@keyframes kicker-shine {
  0% { background-position: 0% 0%; }
  100% { background-position: 100% 0%; }
}
/* animation-direction:alternate (set wherever this keyframe is used)
   is what actually makes the loop seamless — not the color match at
   the gradient's two ends. animation:...infinite alone (direction:
   normal) jumps 100%->0% instantly every cycle, and even though both
   ends are the same dark green, that jump changes WHICH slice of the
   oversized (300%) background is visible, not just its color at the
   edge, so it read as a hard cut ("reinicia brutalmente"). alternate
   reverses direction at each end instead of jumping, so motion never
   discontinues — the shine sweeps right, then smoothly sweeps back
   left, forever. */
/* Same green metallic text-clip as .hero-kicker, factored out as its
   own reusable class for highlighting a single word inline elsewhere
   ("a palavra negócio deve ter a cor verde e o efeito metalizado de
   luz que já existe em alguns botões") — everything except the
   full-line text-align-last:justify stretch, which only makes sense
   for .hero-kicker's own single-line layout. */
.text-shine-green {
  background: linear-gradient(95deg, #0e5c34 0%, #1fae52 18%, #6dffb0 40%, #eafff2 50%, #6dffb0 60%, #1fae52 82%, #0e5c34 100%);
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 0 18px rgba(52,224,122,.35);
}
/* Same technique, brand-orange tones instead of green ("na palavra
   credibilidade tenha aquele efeito metalizado") — the bright band
   near the middle is a warm near-white rather than pure white so it
   still reads as "orange metal" catching light, not a different hue
   sneaking in. */
.text-shine-orange {
  background: linear-gradient(95deg, #7a3300 0%, #e25400 18%, #ff9a3d 40%, #fff2e0 50%, #ff9a3d 60%, #e25400 82%, #7a3300 100%);
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 0 18px rgba(255,106,0,.4);
}
.hero-tagline {
  position: relative;
  display: inline-block;
  color: var(--text-muted);
  font-weight: 300;
  font-size: clamp(1.05rem, 1.8vw, 1.3rem);
  letter-spacing: .01em;
  max-width: 620px;
  margin: 20px 0 32px;
}
.hero-tagline strong {
  color: var(--orange);
  font-weight: 700;
}
.hero-tagline::before {
  content: '';
  position: absolute;
  top: -14px;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--orange);
}
.hero-sub {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  color: var(--text-muted);
  font-size: 1.1rem;
  max-width: 480px;
  margin-bottom: 34px;
}
.word-swap {
  position: relative;
  display: inline-block;
}
.word-swap-item {
  position: relative;
  transition: opacity .1s ease;
}
.word-swap-item:not(.is-active) {
  position: absolute;
  inset: 0;
  opacity: 0;
}

/* Word-swap glitch (v2, 30/08): a short (~1.3s), multi-pulse digital
   interference instead of the old single skew/shake "blink". Three
   layers do the work, all driven purely by class toggles from main.js
   (no JS-computed styles):
   1) .word-swap itself gets a small ambient jitter for the whole 1.3s
      window (glitch-ambient) — ties the before/after together.
   2) the OUTGOING word gets a short "glitching-out" burst right before
      the swap (glitch-burst, forward) — clip-path tears + RGB-split
      duplicate slivers via ::before/::after, escalating.
   3) the INCOMING word gets the *same* burst keyframe played in
      `reverse` right after the swap (glitch-burst, reverse) — starts
      fragmented, settles to clean. Reusing one keyframe both ways keeps
      this from turning into a pile of near-duplicate animations.
   Each burst is a fresh, independent animation instance (not a
   continuation of glitch-ambient's timeline), so it restarting at 0%
   when the class is added is correct, not a bug — it's a deliberate
   entrance/exit, not a resumed animation. */
.word-swap.is-glitching {
  animation: glitch-ambient 1.3s linear 1;
}
.word-swap-item.is-glitching-out {
  animation: glitch-burst 340ms linear 1;
}
.word-swap-item.is-glitching-in {
  animation: glitch-burst 350ms linear 1 reverse;
}
.word-swap-item.is-glitching-out::before,
.word-swap-item.is-glitching-out::after,
.word-swap-item.is-glitching-in::before,
.word-swap-item.is-glitching-in::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.word-swap-item.is-glitching-out::before,
.word-swap-item.is-glitching-in::before {
  color: #fff;
  animation: glitch-slice-white 340ms linear 1;
}
.word-swap-item.is-glitching-out::after,
.word-swap-item.is-glitching-in::after {
  animation: glitch-slice-color 340ms linear 1;
}
@keyframes glitch-ambient {
  0%, 8%, 100% { transform: translate(0, 0); }
  3% { transform: translate(1px, -1px); }
  20% { transform: translate(-1px, 1px); }
  24% { transform: translate(1px, 0); }
  28% { transform: translate(0, 0); }
  86% { transform: translate(1px, -1px); }
  90% { transform: translate(-1px, 0); }
  94% { transform: translate(0, 0); }
}
@keyframes glitch-burst {
  0% { transform: translate(0, 0); clip-path: inset(0 0 0 0); opacity: 1; }
  15% { transform: translate(-3px, 1px); clip-path: inset(8% 0 62% 0); }
  30% { transform: translate(4px, -2px); clip-path: inset(48% 0 12% 0); }
  45% { transform: translate(-4px, 2px); clip-path: inset(20% 0 55% 0); opacity: .9; }
  60% { transform: translate(3px, -1px); clip-path: inset(60% 0 5% 0); }
  75% { transform: translate(-2px, 1px); clip-path: inset(10% 0 68% 0); opacity: .95; }
  90% { transform: translate(1px, 0); clip-path: inset(0 0 0 0); }
  100% { transform: translate(0, 0); clip-path: inset(0 0 0 0); opacity: 1; }
}
@keyframes glitch-slice-white {
  0%, 100% { opacity: 0; transform: translate(0, 0); clip-path: inset(50% 0 50% 0); }
  20% { opacity: .55; transform: translate(-3px, 0); clip-path: inset(15% 0 65% 0); }
  35% { opacity: 0; }
  55% { opacity: .5; transform: translate(3px, -1px); clip-path: inset(60% 0 10% 0); }
  70% { opacity: 0; }
}
@keyframes glitch-slice-color {
  0%, 100% { opacity: 0; color: #ff5470; transform: translate(0, 0); clip-path: inset(50% 0 50% 0); }
  25% { opacity: .6; color: #ff5470; transform: translate(4px, 0); clip-path: inset(58% 0 15% 0); }
  40% { opacity: 0; }
  65% { opacity: .5; color: #5fd8ff; transform: translate(-3px, 1px); clip-path: inset(12% 0 60% 0); }
  80% { opacity: 0; }
}
/* No prefers-reduced-motion override here on purpose — like the orbit
   spin below, the glitch is decorative but the motion IS the effect,
   so it keeps playing even when the OS/browser asks for reduced motion. */

.hero-actions { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
/* "Ver serviços" doesn't need to be a button — ("não precisa ser um
   botão, pode ser apenas clicável") — a plain underlined link next to
   the WhatsApp CTA instead of a second competing button. */
.hero-see-services {
  color: var(--text-muted);
  font-weight: 500;
  font-size: .95rem;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: rgba(255,255,255,.3);
  transition: color .2s ease, text-decoration-color .2s ease;
}
.hero-see-services:hover {
  color: var(--text);
  text-decoration-color: var(--text);
}

.hero-title-group { transform-origin: center top; }

.hero-visual {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.glow {
  position: absolute;
  width: 340px; height: 340px;
  background: radial-gradient(circle, rgba(255,106,0,.32), transparent 70%);
  filter: blur(10px);
  z-index: 0;
}
/* The orbiting icon ring that used to sit behind the rocket was removed
   30/08 (the Wendell wants to reuse it in a different section later) —
   the full HTML/CSS is saved verbatim in contexto.md ("Snippet salvo:
   anel giratório de ícones") along with what a new host element needs
   to declare (--r-inner/--r-outer) for it to work again. Don't rebuild
   it from scratch if asked to bring it back — copy that snippet. */

/* The hero centerpiece: the Ideals logo with an orange glow that hugs
   its own letterforms (stacked drop-shadows follow the image's alpha
   shape, unlike a generic circular gradient blob), with the icon rings
   orbiting around/behind it. Replaced an actual photo here — a
   person's irregular silhouette kept fighting the orbit icons (rough
   edges, icons blending into faded hair/shoulders). A clean logo PNG
   has none of that: simple shape, flat alpha, nothing to fade
   unevenly, so it plays nicely with icons passing behind it. */
.hero-emblem {
  position: relative;
  z-index: 2;
  width: clamp(360px, 68vw, 1050px);
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Irregular step positions + varied translate/rotate signs (not a
   clean 4-beat back-and-forth) so the drift reads as organic wobble
   rather than a mechanical cycle ("movimentação... aleatória"). Range
   widened and duration slowed on desktop feedback ("está boa, porém
   preciso que se mexa em um espaço maior e mais devagar" — started at
   sub-pixel/2.4s, now a few px / half a degree over 5s). 0%/100% still
   share the exact same transform, so the loop wraps with zero jump no
   matter how many times it repeats ("o looping não seja cortado
   bruscamente... suave e reiniciado"), same principle as the
   kicker/WhatsApp button shine elsewhere in this file. Started
   desktop-only by request ("pelo menos na versão desktop, não precisa
   ser pra mobile"), later asked for on mobile too — now runs at every
   width (see the plain, unscoped `animation` declaration below). */
@keyframes rocket-shake {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  8%  { transform: translate(4px, -3px) rotate(.6deg); }
  19% { transform: translate(-3px, 2px) rotate(-.35deg); }
  33% { transform: translate(5px, 1.5px) rotate(.45deg); }
  47% { transform: translate(-3.5px, -3px) rotate(-.55deg); }
  61% { transform: translate(2px, 4px) rotate(.3deg); }
  74% { transform: translate(-4.5px, 1px) rotate(-.4deg); }
  88% { transform: translate(2.5px, -2px) rotate(.35deg); }
}
.hero-emblem img {
  width: 100%;
  height: auto;
  display: block;
  filter:
    drop-shadow(0 16px 32px rgba(0,0,0,.35))
    drop-shadow(0 0 18px rgba(255,106,0,.55))
    drop-shadow(0 0 42px rgba(255,106,0,.35));
  /* Same reasoning as .hero-earth above: a big image with a triple
     drop-shadow stack, scrolling in normal flow with no compositing
     hint, is expensive to keep re-rasterizing on every scroll frame.
     Pin it to its own GPU layer instead. */
  will-change: transform;
}
/* Now runs at every width — originally desktop-only by request, but
   asked for on mobile too ("adicione a animação do foguete que está no
   desktop na versão para mobile também"). */
.hero-emblem img { animation: rocket-shake 5s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .hero-emblem img { animation: none; }
}


/* ==========================================================
   Section shared — every section sits on the same --bg,
   so there are no hard color seams between them. Depth comes
   from --surface cards, not section-level color blocking.
   ========================================================== */
section { padding: 100px 0; background: transparent; }
.section-tag {
  color: var(--orange);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  font-size: 0.85rem;
  margin-bottom: 10px;
  position: relative;
  padding-left: 26px;
}
.section-tag::before {
  content: '';
  position: absolute;
  left: 0; top: 50%;
  transform: translateY(-50%);
  width: 18px; height: 2px;
  background: var(--orange);
}
.section-title { font-size: clamp(1.8rem, 3.2vw, 2.6rem); }
/* Peso 300 ("fonte mais fininha") — o Poppins já é carregado com o 300,
   então não entra requisição nova. Aplicado a TODOS os .section-lead do
   site, não só ao da seção de preços: um parágrafo fino no meio de
   vários normais destoaria. */
.section-lead { max-width: 560px; font-size: 1.05rem; font-weight: 300; }

/* Services */
.services { text-align: center; }
/* .section-tag's ::before dash (see below) is meant as a left-aligned
   prefix mark — works fine in .about/.differentials/.contato, but here
   .section-tag is centered, so the dash floats disconnected off to the
   left of the text instead of reading as a prefix. Removed just for
   this section per explicit request ("esse risco solto"). */
.services .section-tag { padding-left: 0; }
.services .section-tag::before { display: none; }
/* Keeps the services content above the .hero-earth bleed (z-index:1) —
   without this, the earth (a positioned sibling from the hero) would
   paint over these non-positioned cards despite coming later in the
   document, since positioned elements paint after normal-flow ones. */
.services .container { position: relative; z-index: 2; }
.services .section-lead { margin: 0 auto 56px; }
.services-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
  text-align: left;
}
/* Hidden by default via the [hidden] attribute in HTML; main.js shows
   it only when a hero search has 0 matching cards. WhatsApp href gets
   the visitor's own search text prefilled in — see main.js. */
.services-no-match {
  margin: 32px 0 0;
  padding: 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  text-align: center;
}
.services-no-match[hidden] { display: none; }

/* Botão "Ver preços": leva pros planos da /landing-pages/, que é onde os
   valores moram. Fica depois da grade e antes do aviso de busca sem
   resultado, no ponto em que a pergunta "quanto custa" aparece. */
.services-precos {
  display: flex;
  justify-content: center;
  margin-top: 44px;
}
@media (max-width: 720px) {
  .services-precos { margin-top: 30px; }
  .services-precos .btn { width: 100%; max-width: 340px; justify-content: center; }
}
/* Each card is a themed illustration (see assets/img/services/) that
   fades into the card's own --surface color on all four sides before
   it ever reaches the card's edge — not a cropped/framed image, the
   art itself dissolves outward. Done with 4 stacked linear-gradients
   (one per edge) painted over the image in a single background-image
   list, deliberately not mask-image (see the note above
   .btn-whatsapp and the earth's remove-checkerboard.js history:
   masking has broken twice before in this project; gradients have
   not). The bottom gradient is taller/stronger than the other three
   so the title/description always land on a clean, legible strip no
   matter how busy that illustration is; top/left/right just need
   enough fade that the art doesn't visibly touch the border.
   --accent drives the icon/badge/hover colors per card (set via the
   --orange/--purple/etc. modifier classes below via --art + --accent),
   so the accent always matches that card's own illustration instead
   of every card defaulting to brand orange. */
.service-card {
  position: relative;
  z-index: 0; /* contains the ::before's negative z-index layer to
    this card's own local stacking context — without it, position:
    relative alone (no z-index) doesn't create a stacking context and
    the layer could escape to paint behind unrelated page content. */
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: clamp(300px, 35vw, 420px);
  background-color: var(--surface);
  border-radius: var(--radius);
  padding: 28px;
  transition: transform .4s ease, box-shadow .5s ease, border-color .4s ease, opacity .3s ease, filter .3s ease;
  border: 1px solid var(--border);
  --accent: var(--orange);
  --accent-soft: rgba(255,106,0,.16);
  /* Where the interesting part of --art actually sits within its own
     canvas — "center" assumes the illustration is centered on its own
     transparent canvas, which isn't true for every asset (loja-virtual.png
     has the storefront pushed into the right half, empty space on the
     left, so a plain center crop cuts off-center). Override per card
     below only where the source needs it. */
  --art-pos: center;
  /* Zoom level for --art specifically — "cover" is the minimum size
     that fills the card with no gaps, but if the illustration's own
     subject only occupies part of ITS canvas (empty space around it),
     cover alone can leave the subject looking small/distant. A single
     percentage value here scales by container width and lets height
     resolve to `auto`, preserving the source's own aspect ratio (no
     stretch) while sizing past cover's minimum. Override per card
     only where the source needs the extra zoom. */
  --art-size: cover;
}
.service-card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(to bottom, var(--surface) 0%, transparent 16%),
    linear-gradient(to bottom, transparent 28%, var(--surface) 88%),
    linear-gradient(to right, var(--surface) 0%, transparent 14%),
    linear-gradient(to left, var(--surface) 0%, transparent 14%),
    var(--art);
  background-size: cover, cover, cover, cover, var(--art-size);
  background-position: center, center, center, center, var(--art-pos);
}
/* Under-light ("um ponto de luz que vai abaixo do texto... começa na
   borda inferior de cada card com a sua respectiva cor... iluminando o
   texto ali por baixo, como se fosse uma iluminação que vem de
   baixo... mais um [glow] do que um ponto de luz específico") — a wide
   wash rising from the card's own bottom edge, not a localized point
   (that was the earlier corner beam/blob, removed after it read as
   "horrível"/"muito forte"). Full-width linear-gradient instead of a
   positioned/rotated shape, so there's nothing to anchor or clip
   awkwardly. Fades out by the gradient's own halfway point, which
   lands right around where .service-card::before's own fade-to-surface
   already sits (see the "transparent 28%" stop above) — so the color
   is warming an area that's already mostly flat --surface behind the
   text, instead of fighting the illustration higher up. Screen blend
   at low opacity keeps it a soft ambient wash, not a wash of flat
   color. Sits above the illustration/fade layer (z-index:-1) but below
   the text (.service-card > *, z-index:1). */
.service-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(to top, var(--accent) 0%, transparent 55%);
  mix-blend-mode: screen;
  opacity: .4;
}
.service-card > * { position: relative; z-index: 1; }
.service-card:hover {
  transform: scale(1.04);
  border-color: var(--accent);
  /* Layered glow instead of a flat border-color swap: a dark lift
     shadow underneath, a tight soft ring right at the edge, and a
     wide, low-opacity halo bleeding out past the card — all using
     each card's own --accent-soft (already a low-alpha version of its
     accent), so the color matches per card without a new token. Two
     glow layers at different blur radii read as a proper soft light
     source instead of one hard-edged ring; the slower .5s box-shadow
     transition (up from .22s) is what actually reads as "smoother" —
     a snappy transition on a shadow this size looks like a flicker. */
  box-shadow:
    0 20px 40px rgba(0,0,0,.3),
    0 0 0 1px var(--accent-soft),
    0 0 30px 4px var(--accent-soft),
    0 0 70px 14px var(--accent-soft);
}
/* Hero search states (02/09, see main.js) — a match reuses the exact
   :hover glow above (so "matched" reads as "as if you're already
   hovering it"); a non-match just dims/desaturates rather than being
   removed from the grid, since keyword matching is approximate and an
   empty-looking grid would read as "no results" even when it's really
   "no exact match". opacity fades the whole card including its own
   box-shadow, so .service-card--popular's pulse dims along with it
   with no extra rule needed. */
.service-card.is-match {
  border-color: var(--accent);
  box-shadow:
    0 20px 40px rgba(0,0,0,.3),
    0 0 0 1px var(--accent-soft),
    0 0 30px 4px var(--accent-soft),
    0 0 70px 14px var(--accent-soft);
}
.service-card.is-dimmed { opacity: .35; filter: saturate(.6); }
/* "Mais procurado" card gets a permanent breathing glow instead of
   only lighting up on hover — it's already visually singled out
   (border-color always on), so the pulse reads as "this one's the
   highlight" at a glance, even before the user touches anything.
   Same accent-soft glow layers as the shared :hover effect, just
   oscillating on a loop instead of snapping in on pointer-enter — a
   running CSS animation owns box-shadow for as long as it's active,
   so :hover's own box-shadow declaration has no visible effect here
   while this plays, which is fine: the constant pulse already does
   that card's "look at me" job. Decorative loop, no motion IS the
   feature — same reasoning as orbit-spin/glitch, no
   prefers-reduced-motion override. */
.service-card--popular {
  border-color: var(--accent);
  animation: popular-pulse 2.6s ease-in-out infinite;
}
@keyframes popular-pulse {
  0%, 100% {
    box-shadow: 0 0 0 1px var(--accent-soft), 0 0 20px 2px var(--accent-soft);
  }
  50% {
    box-shadow: 0 0 0 1px var(--accent-soft), 0 0 45px 10px var(--accent-soft), 0 0 90px 20px var(--accent-soft);
  }
}
.service-card--orange { --art: url('../img/services/landing-pages.png'); }
.service-card--purple { --accent: #9b5fff; --accent-soft: rgba(155,95,255,.18); --art: url('../img/services/criativos.png'); }
.service-card--yellow { --accent: #f5b942; --accent-soft: rgba(245,185,66,.18); --art: url('../img/services/trafego-pago.png'); --art-pos: 66% 47%; --art-size: 260%; }
.service-card--green  { --accent: #22c55e; --accent-soft: rgba(34,197,94,.18); --art: url('../img/services/loja-virtual.png'); --art-pos: 68% 55%; --art-size: 200%; }
.service-card--blue   { --accent: #3b82f6; --accent-soft: rgba(59,130,246,.18); --art: url('../img/services/edicao-video.png'); }
.service-badge {
  position: absolute;
  top: 24px;
  right: 24px;
  z-index: 1;
  background: rgba(255, 106, 0, .16);
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid rgba(255, 106, 0, .55);
  box-shadow: 0 0 16px rgba(255, 106, 0, .24), inset 0 0 10px rgba(255,255,255,.05);
  animation: badge-pulse 2.6s ease-in-out infinite;
}
@keyframes badge-pulse {
  0%, 100% { box-shadow: 0 0 12px rgba(255,106,0,.18), inset 0 0 10px rgba(255,255,255,.04); }
  50% { box-shadow: 0 0 24px rgba(255,106,0,.42), inset 0 0 10px rgba(255,255,255,.08); }
}
/* 5 cards total: the first 3 fill row 1, then Loja Virtual (1 col)
   and this one (2 cols) fill row 2 — grid auto-placement handles the
   packing on its own, no explicit row/column needed. Bigger by request
   ("um deles vai ter que ser maior... o de edição de vídeo"), taking
   over the space of the 6th card that was removed. */
.service-card--featured {
  grid-column: span 2;
  padding: 34px 36px;
}
.service-card--featured h3 { font-size: 1.3rem; }
.service-card--featured p { max-width: 480px; }
.service-card h3 { font-size: 1.15rem; margin-bottom: 8px; }
.service-card p { font-size: 0.95rem; margin: 0; color: var(--text-muted); }

/* Each card is now an <a> instead of a plain <article> — CSS selectors
   above are all class-based (.service-card, .service-card--popular,
   .service-card::before...), none scoped to the `article` tag, so this
   swap needed zero rule changes. Cursor is the browser's own anchor
   default; the two lines below just stop link/visited defaults (native
   text-decoration, non-inherited color) from leaking onto the card. */
.service-card { text-decoration: none; }
.service-card:visited { color: var(--text); }

/* Service placeholder pages (assets/service-page.css-free — kept in the
   main stylesheet so /criativos, /trafego-pago etc. share one <link>
   with the homepage instead of a second stylesheet to keep in sync).
   Each page sets --accent/--accent-soft inline via style="" using the
   exact same hex pairs as that service's .service-card--* modifier
   above, so the icon/eyebrow/glow always match the card it came from. */
.service-placeholder {
  min-height: calc(100vh - 78px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 120px 24px;
  position: relative;
  z-index: 2; /* stay above .hero-earth-style bleed, same reasoning as
    .services .container above */
  text-align: center;
}
.service-placeholder-inner { max-width: 620px; }
.service-placeholder-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 84px;
  height: 84px;
  margin: 0 auto 28px;
  border-radius: 20px;
  background: var(--accent-soft);
  color: var(--accent);
  backdrop-filter: blur(6px);
  box-shadow: 0 0 60px 4px var(--accent-soft);
}
.service-placeholder-icon svg { width: 40px; height: 40px; }
.service-placeholder .section-tag {
  justify-content: center;
  display: inline-flex;
  color: var(--accent);
}
.service-placeholder .section-tag::before { background: var(--accent); }
.service-placeholder h1 {
  font-size: clamp(2rem, 5vw, 2.9rem);
  margin-bottom: 18px;
}
.service-placeholder-lead {
  font-size: 1.05rem;
  max-width: 460px;
  margin: 0 auto 36px;
}
.service-placeholder-actions {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
}
@media (max-width: 520px) {
  .service-placeholder-actions { flex-direction: column; align-items: stretch; }
  .service-placeholder-actions .btn { justify-content: center; }
}

/* ==========================================================
   Landing Pages service page (02/09) — real content replacing
   the "em breve" placeholder. Reuses existing components wherever
   the pattern already exists (.dif-grid/.dif-item for the process
   steps, .hero-stats-item for the results, .contact/.contact-inner
   for the closing CTA) — only genuinely new pieces get new CSS
   below: the hero layout and the deliverables checklist. (The hero
   originally had its own signature mockup here too — a fake browser
   window with an auto-looping cursor/click — removed 05/09 in favor
   of a real carousel of finished pages instead, see
   .lp-carousel-placeholder below.)
   ========================================================== */
/* 150px -> 100px -> 72px -> 48px across rounds of "suba mais esse
   conjunto" and finally "preciso que caiba tudo na primeira seção".
   The header is position:sticky, so it occupies its own 78px of layout
   at the top — this padding is pure gap below it, and cutting it can't
   push anything underneath the header. The bottom padding is trimmed
   from the section default too: it sits below the carousel, so it
   doesn't fight the fold, but 100px there just padded the page out.
   Everything in this hero is on a tight vertical budget now; measured
   at 1440x900 the whole block (header through dots) lands around 760px,
   leaving room to spare. */
.lp-hero {
  padding-top: 48px;
  padding-bottom: 64px;
  /* O hero ocupa a tela inteira pra que a seção seguinte nunca espie
     por baixo ("a segunda seção está aparecendo antes da hora"). Como
     todo o conteúdo já cabe acima da dobra, isso não empurra nada — só
     garante que a borda entre as duas seções caia no fim da tela, em
     qualquer altura de janela. svh (a altura da viewport COM a barra do
     navegador aberta) é a medida conservadora no celular; vh fica como
     reserva pra quem não suporta. */
  min-height: 100vh;
}
@supports (min-height: 100svh) {
  .lp-hero { min-height: 100svh; }
}
/* 05/09: switched from a 2-column grid (copy left, static mockup
   right) to a single centered column — "o título ficará em uma linha
   só e centralizado, abaixo dele terá aquela search bar, e abaixo da
   search bar terá a frase 'landing pages rápidas...'". The DOM order
   already matched this (h1 -> .hero-search -> .hero-search-hint ->
   .section-lead), so centering the column was the actual change
   needed, not reordering markup. Applies at every width now, not just
   the old mobile-only override. */
.lp-hero-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 28px;
}
.lp-hero-copy { width: 100%; }
/* Smaller cap than the old 2.9rem — that size only fit one line
   ("o título ficará em uma linha só") when the phrase had a whole
   2-column-grid's worth of extra room; centered full-width it still
   wrapped to two lines at the old size, so the cap came down until it
   actually held one line at typical desktop widths (checked via
   Playwright at 1440px, not eyeballed). */
.lp-hero-copy h1 { font-size: clamp(1.7rem, 3.6vw, 2.4rem); margin: 0 0 14px; }
/* Comprimento de linha legivel quando centralizado em largura total. */
.lp-hero-copy .section-lead { max-width: 640px; margin: 0 auto 24px; }
/* .hero-search-hint's default -14px top margin exists to hug a search
   box that carries its own 26px bottom margin — here .lp-search-row
   handles that spacing instead, so the negative pull would drag the
   caption up into the row. */
/* O respiro maior comeca aqui, na frase abaixo da busca — a folga que o
   hero de 100svh deixou embaixo e o que paga por isso. */
.lp-hero .hero-search-hint { margin: 0 0 34px; }
/* Search bar + WhatsApp contact on one centered line. The bar itself
   is wider and squarer than the homepage's ("deixa a search bar mais
   larga e menos arredondada" — 480px pill -> 680px at the same 18px
   radius the buttons use), and the row (not margin:auto) is what
   centers the pair as a unit. */
.lp-search-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-bottom: 8px;
}
.lp-hero .hero-search {
  flex: 1 1 auto;
  /* Without this the bar refuses to shrink past its automatic minimum
     size (the text input carries an intrinsic width), so on a phone it
     kept its full width and pushed itself and the contact icon off
     both edges of the screen — "a search bar tem que caber na tela". */
  min-width: 0;
  max-width: 680px;
  border-radius: 18px;
  margin: 0;
  /* Slimmer than the homepage's bar ("pode deixar a barra de pesquisa
     mais fina") — the height comes from these paddings plus the
     input's own, trimmed together just below. */
  padding: 5px 5px 5px 18px;
}
.lp-hero .hero-search-input { padding: 9px 0; }
/* "Criar" sits inside the bar, on the right, carrying the Ideals mark
   (the favicon) — it submits whatever's typed instead of waiting for
   the input's own character threshold (see main.js). */
.hero-search-create {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border: none;
  border-radius: 13px;
  background: var(--surface-2);
  color: var(--text);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .25s ease, transform .2s ease;
}
.hero-search-create img { width: 20px; height: 20px; object-fit: contain; }
@media (hover: hover) and (pointer: fine) {
  .hero-search-create:hover { background: rgba(255,106,0,.18); }
}
/* WhatsApp mark + "Contato" underneath, outside the bar to its right
   ("ao lado direito e fora da search bar... em uma versão PNG escrito
   'contato' abaixo dele"). Full-color PNG here rather than the white
   glyph used inside green buttons — this one stands on the page's own
   dark background, so it needs its own color. */
/* Sized to sit just under the search bar's own height ("isso tem que
   estar levemente menor que a search bar") — icon + gap + label lands
   around 44px against the bar's ~50px, so it reads as a companion to
   the bar rather than competing with it. */
.lp-contact-icon {
  flex-shrink: 0;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  font-size: 0.62rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text-muted);
  transition: transform .2s ease, color .2s ease;
}
.lp-contact-icon img { width: 30px; height: 30px; object-fit: contain; }
@media (hover: hover) and (pointer: fine) {
  .lp-contact-icon:hover { transform: translateY(-2px); color: var(--text); }
}
/* align-items:center matters now that the second action is plain text
   ("pode remover as bordas, que seja mais um texto clicável", same
   treatment "Ver serviços" already got on the home) instead of a
   button — stretch would leave the link's underline sitting at the
   bottom of the green button's height rather than beside its label. */
.lp-hero-actions { display: flex; gap: 22px; flex-wrap: wrap; justify-content: center; align-items: center; margin-top: 30px; }


/* ==========================================================
   Planos / valores (/landing-pages/)
   Cada card herda a cor do serviço correspondente na home
   (.service-card--*), então a paleta não é nova: é a mesma que a
   pessoa já viu na grade de serviços. --accent pinta ícone, tagline,
   marcadores da lista e o botão, o que faz cada card se identificar
   sozinho sem precisar de rótulo extra.
   ========================================================== */
/* Cabeçalho centralizado, cards alinhados à esquerda — igual à seção
   de pilares logo abaixo. E, centralizado, o traço do .section-tag
   volta a flutuar solto longe do texto (mesmo caso já corrigido em
   .services, .reviews, no hero da LP e em .lp-includes). */
.lp-plans { text-align: center; padding-top: 76px; }
/* O olho-magico sobe (padding-top menor que o padrao de section) e ganha
   um fio fino separando ele do titulo. O fio some nas pontas por
   gradiente em vez de terminar seco — mesma ideia do fade do carrossel
   de avaliacoes. */
.lp-plans .section-tag {
  position: relative;
  margin-bottom: 26px;
  padding-bottom: 15px;
}
.lp-plans .section-tag::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: 62px;
  height: 1px;
  background: linear-gradient(to right, transparent, rgba(255,255,255,.3), transparent);
}
.lp-plans .section-tag { padding-left: 0; }
.lp-plans .section-tag::before { display: none; }
.lp-plans .section-lead { max-width: 620px; margin: 0 auto 48px; }
/* Flex-wrap with centred rows instead of a grid: five is an awkward
   count for a column layout — any grid that fits four per row leaves
   the fifth stranded alone on the left of the next one. Wrapping with
   justify-content:center makes every intermediate width (5, then 4+1,
   3+2, 2+2+1) look deliberate instead of orphaned, and it keeps working
   if the service list ever grows or shrinks. The 200px basis is what
   lets all five sit on one row on a desktop container. */
.lp-plans-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 18px;
  text-align: left;
}
.lp-plan {
  flex: 1 1 200px;
  max-width: 260px;
  display: flex;
  flex-direction: column;
  padding: 26px 22px 24px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  /* Fundo com textura em vez de chapado ("o fundo está muito seco"):
     um brilho da cor do serviço sangrando da borda de cima, mais a
     mesma trama de pontinhos usada no .hero-stats do mobile e no
     .bg-fx. A cor sai do --accent de cada card, então os quatro têm o
     mesmo tratamento sem nenhum gradiente escrito à mão. */
  background-color: var(--surface);
  background-image:
    radial-gradient(120% 85% at 50% -12%, var(--accent-soft), transparent 62%),
    radial-gradient(rgba(255,255,255,.05) 1px, transparent 1.5px);
  background-size: auto, 16px 16px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07);
  transition: transform .3s ease, border-color .3s ease;
}
@media (hover: hover) and (pointer: fine) {
  .lp-plan:hover { transform: translateY(-4px); border-color: var(--accent-soft); }
}
.lp-plan--orange { --accent: var(--orange); --accent-soft: rgba(255,106,0,.18); }
.lp-plan--purple { --accent: #9b5fff; --accent-soft: rgba(155,95,255,.18); }
.lp-plan--yellow { --accent: #f5b942; --accent-soft: rgba(245,185,66,.18); }
.lp-plan--green  { --accent: #22c55e; --accent-soft: rgba(34,197,94,.18); }
.lp-plan--blue   { --accent: #3b82f6; --accent-soft: rgba(59,130,246,.18); }
/* Criação de Site é serviço novo (não tem card na home), então é a
   única cor daqui que não vem de lá. */
.lp-plan--cyan   { --accent: #22d3ee; --accent-soft: rgba(34,211,238,.18); }
.lp-plan-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  margin-bottom: 16px;
  border-radius: 11px;
  background: var(--accent-soft);
  color: var(--accent);
}
.lp-plan-icon svg { width: 20px; height: 20px; }
/* CAPS nos títulos dos cards. A fonte segue Poppins: a Cocogoose da
   identidade é paga e não está no projeto (ver Tipografia no
   contexto.md) — se o arquivo licenciado entrar em assets/fonts/, é um
   @font-face e trocar a --font. Fonte um pouco menor e letter-spacing
   um pouco maior porque maiúscula ocupa mais largura e fecha demais com
   o espaçamento normal. */
.lp-plan h3 {
  font-size: 0.95rem;
  margin: 0 0 10px;
  text-transform: uppercase;
  letter-spacing: .02em;
}
.lp-plan-tagline {
  margin: 0 0 8px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--accent);
}
.lp-plan-desc { margin: 0 0 18px; font-size: 0.88rem; }
.lp-plan-list {
  list-style: none;
  margin: 0 0 22px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.lp-plan-list li {
  position: relative;
  padding-left: 18px;
  font-size: 0.85rem;
  color: var(--text);
}
.lp-plan-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 8px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
/* margin-top:auto puts the price/CTA block on the card's floor, so the
   five prices line up across the row no matter how long each
   description or list runs. */
.lp-plan-from {
  margin: auto 0 2px;
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.lp-plan-price {
  margin: 0 0 16px;
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--text);
}
/* "Sob consulta" entra no lugar do preço, sem o "A partir de" acima —
   por isso ele carrega o margin-top:auto que normalmente é do
   .lp-plan-from, pra continuar ancorado no rodapé do card. */
.lp-plan-price--quote {
  margin-top: auto;
  font-size: 1.15rem;
  color: var(--text-muted);
}
/* Metalizado sem escrever um gradiente por cor: o brilho é uma camada
   translúcida (preto nas pontas, branco no meio) POR CIMA da cor sólida
   do card, então o mesmo bloco serve pros quatro accents e continuaria
   servindo se aparecer um quinto. É a mesma mecânica do .btn-whatsapp e
   dos .text-shine-* — background-size 300% + a keyframe kicker-shine
   deslizando o background-position —, só que aqui a cor de baixo vem do
   --accent em vez de estar embutida no gradiente.
   background-color e background-image separados de propósito: o
   shorthand `background` zera o background-size, que é justamente o que
   faz o brilho ter pra onde correr. */
.lp-plan-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 18px;
  border-radius: 12px;
  background-color: var(--accent);
  background-image: linear-gradient(115deg,
    rgba(0,0,0,.28) 0%,
    rgba(255,255,255,.10) 20%,
    rgba(255,255,255,.55) 40%,
    rgba(255,255,255,.10) 60%,
    rgba(0,0,0,.28) 100%);
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  color: #0b0b0d;
  font-size: 0.88rem;
  font-weight: 700;
  text-shadow: 0 1px 3px rgba(255,255,255,.25);
  transition: filter .25s ease, transform .2s ease;
  -webkit-tap-highlight-color: transparent;
}
@media (prefers-reduced-motion: reduce) {
  .lp-plan-cta { animation: none; }
}
@media (hover: hover) and (pointer: fine) {
  .lp-plan-cta:hover { filter: brightness(1.12); }
}
@media (max-width: 720px) {
  .lp-plans-grid { gap: 16px; }
  /* Uma coluna de verdade, com todos os cards na MESMA largura. Antes
     aqui havia grid-template-columns:1fr, que não faz nada: a grade virou
     flex. Sobravam os limites do desktop — 260px nos cards e 320px no
     triplo —, e numa tela de 439px o card ficava com ~90px de vão de
     cada lado e o triplo mais largo que os outros. O teto de 440px é pra
     que, perto dos 720px, o card não estique até virar faixa.
     .lp-plans-grid na frente de propósito: sem esse peso extra, o
     max-width:320px do .lp-plan--duo (declarado mais abaixo no arquivo)
     venceria esta regra só por vir depois. */
  .lp-plans-grid .lp-plan { flex: 1 1 100%; max-width: 440px; }
  .lp-plans .section-lead { margin-bottom: 32px; }
}

.lp-results-grid { display: flex; gap: 20px; flex-wrap: wrap; margin-top: 8px; }
.lp-results-grid .hero-stats-item { flex: 1 1 220px; }

/* Quatro pilares do "o que está incluso" (3ª seção). O primeiro ocupa
   a linha inteira e os outros três dividem a de baixo — o de cima é o
   que carrega a explicação mais longa, então ganha a largura. */
/* Cabeçalho centralizado, cards alinhados à esquerda. E, centralizado,
   o traço do .section-tag volta a flutuar solto longe do texto — mesmo
   caso já corrigido em .services, .reviews e no hero da LP. */
/* A seção inteira precisa caber numa tela ("precisa caber tudo nessa
   seção") — o CTA estava sendo cortado embaixo. Daí o padding menor que
   o padrao de section e os espaçamentos internos apertados abaixo. */
.lp-includes { text-align: center; padding-top: 64px; padding-bottom: 64px; }
.lp-includes .section-tag { padding-left: 0; }
.lp-includes .section-tag::before { display: none; }
.lp-includes .section-lead { max-width: 620px; margin: 0 auto 28px; }
.lp-pillars {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  text-align: left;
}
.lp-pillar {
  position: relative;
  overflow: hidden;
  padding: 20px 20px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}
.lp-pillar--wide { grid-column: 1 / -1; }
/* O numeral é ornamento, não informação: fica atrás do conteúdo, bem
   apagado, e sai da árvore de acessibilidade (aria-hidden no HTML). */
.lp-pillar-num {
  position: absolute;
  top: 10px;
  right: 18px;
  font-size: 2.4rem;
  font-weight: 800;
  line-height: 1;
  color: rgba(255,255,255,.05);
  pointer-events: none;
}
.lp-pillar-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  margin-bottom: 12px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
}
.lp-pillar-icon svg { width: 21px; height: 21px; }
.lp-pillar h3 { font-size: 1rem; margin: 0 0 8px; }
.lp-pillar p { margin: 0 0 14px; font-size: 0.88rem; }
.lp-pillar--wide p { max-width: 640px; }
.lp-pillar-tags {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.lp-pillar-tags li {
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,.03);
  font-size: 0.72rem;
  color: var(--text-muted);
}
.lp-includes-close {
  margin-top: 28px;
  text-align: center;
}
.lp-includes-close p { margin: 0 0 16px; }
.lp-includes-cta {
  background: var(--orange);
  color: #fff;
  box-shadow: 0 14px 30px rgba(255,106,0,.28);
}
@media (hover: hover) and (pointer: fine) {
  .lp-includes-cta:hover { background: var(--orange-dark); }
}

/* Empurrado pra baixo dentro do hero — o espaco existe porque o hero
   ocupa a tela inteira e o conteudo termina antes. */
.lp-models { width: 100%; margin-top: 40px; }
.lp-models-label {
  margin: 0 0 12px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-muted);
}
/* Carrossel de modelos: painéis desfilando por um ARCO CÔNCAVO.
   A referência não é um cilindro visto por fora — nele a borda de
   DENTRO de cada painel é que vem pra frente, e o arco fecha em
   direção ao centro ("não é pra dentro, é para fora"). No arco certo é
   o contrário: o painel do meio fica de frente e no plano da tela, e
   os das pontas recuam girando ao contrário, com a borda de FORA mais
   próxima — como um telão curvo envolvendo quem olha.
   Testado lado a lado antes de escolher: montar o cilindro e colocar a
   câmera dentro dele também produz essa curvatura, mas aí se vê o VERSO
   dos painéis e o conteúdo aparece espelhado.
   O movimento não é um anel girando: cada painel percorre o mesmo
   caminho (direita → centro → esquerda) com a mesma animação, só que
   defasado por um atraso negativo proporcional à sua posição na fila.
   Isso distribui os painéis pelo arco e emenda sozinho, sem precisar
   duplicar projeto nenhum: quando um sai pela esquerda, já tem outro
   entrando pela direita no mesmo instante. */
.lp-models-stage {
  position: relative;
  width: 100%;
  max-width: 980px;
  margin: 0 auto;
  height: var(--panel-h, 210px);
  /* Teto da largura do painel; o main.js lê daqui. Subiu de 420 pra 520
     porque sobra espaço embaixo do carrossel. */
  --panel-w-max: 520px;
  /* Sem `perspective` aqui e sem `preserve-3d` no anel de propósito —
     ver o comentário do @keyframes abaixo. */
}
.lp-models-ring {
  position: absolute;
  inset: 0;
}
/* Duas decisões aqui, ambas por causa de defeitos que apareceram:

   1. `perspective()` DENTRO do transform de cada painel, em vez de
      `perspective` no palco com `preserve-3d` no anel. Com o espaço 3D
      compartilhado, um painel que avança atravessa fisicamente o plano
      do vizinho e a GPU corta os dois na linha de interseção — era o
      "corte que fica acontecendo quando a imagem vai tomar a frente".
      Com a perspectiva por painel, cada um é achatado na sua própria
      camada e eles se empilham por z-index, sem se cruzar.

   2. z-index animado junto: achatados, a ordem de pintura passa a ser
      a do DOM, e sem isso o painel da frente podia ficar atrás de um
      recuado. Ele sobe 1→2→3 na ida e desce na volta, acompanhando a
      profundidade.

   Os passos de translateX passam de 100% de propósito: 100% é a largura
   de UM painel, então 120% deixa um quinto de painel de folga entre um
   e outro. Esse número foi de 125 → 145 → 120: a 145 ficou "distante
   demais", e o 125 original só parecia colado porque o corte da
   interseção 3D (item 1 acima) ainda estava lá borrando a divisa entre
   um painel e o seguinte. Resolvido o corte, essa folga é a que lê como
   "levemente separadas". translateZ e rotateY crescem junto com o X pra
   que o recuo acompanhe o afastamento. */
@keyframes models-arc {
  0%   { transform: perspective(1150px) translateX(338.0%) translateZ(-430px) rotateY(-38.0deg); opacity: 0; z-index: 1; }
  8%   { opacity: 1; }
  10%  { transform: perspective(1150px) translateX(249.5%) translateZ(-308px) rotateY(-31.4deg); z-index: 1; }
  20%  { transform: perspective(1150px) translateX(173.3%) translateZ(-200px) rotateY(-24.6deg); z-index: 2; }
  30%  { transform: perspective(1150px) translateX(107.7%) translateZ(-109px) rotateY(-17.4deg); z-index: 2; }
  40%  { transform: perspective(1150px) translateX(50.8%) translateZ(-38px) rotateY(-9.7deg); z-index: 3; }
  50%  { transform: perspective(1150px) translateX(0%) translateZ(0px) rotateY(0deg); z-index: 3; }
  60%  { transform: perspective(1150px) translateX(-50.8%) translateZ(-38px) rotateY(9.7deg); z-index: 3; }
  70%  { transform: perspective(1150px) translateX(-107.7%) translateZ(-109px) rotateY(17.4deg); z-index: 2; }
  80%  { transform: perspective(1150px) translateX(-173.3%) translateZ(-200px) rotateY(24.6deg); z-index: 2; }
  90%  { transform: perspective(1150px) translateX(-249.5%) translateZ(-308px) rotateY(31.4deg); z-index: 1; }
  92%  { opacity: 1; }
  100% { transform: perspective(1150px) translateX(-338.0%) translateZ(-430px) rotateY(38.0deg); opacity: 0; z-index: 1; }
}
.lp-model {
  position: absolute;
  top: 0;
  left: 50%;
  width: var(--panel-w, 420px);
  margin-left: calc(var(--panel-w, 420px) / -2);
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.08);
  background: var(--surface);
  box-shadow: 0 24px 50px rgba(0,0,0,.45);
  animation-name: models-arc;
  animation-duration: var(--arc-dur, 26s);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  /* atraso negativo por painel, escrito pelo main.js */
  animation-delay: var(--delay, 0s);
}
@media (prefers-reduced-motion: reduce) {
  .lp-model { animation: none; }
}
.lp-model img { width: 100%; height: auto; display: block; }
.lp-model-tag {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 2;
  padding: 5px 11px;
  border-radius: 999px;
  background: rgba(10,10,12,.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.14);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent);
}
.lp-model-info {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 38px 16px 14px;
  text-align: left;
  background: linear-gradient(to top, rgba(8,8,10,.92) 30%, transparent);
}
.lp-model-info h3 { margin: 0; font-size: 0.92rem; }
.lp-model-metric {
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,.1);
  border: 1px solid rgba(255,255,255,.16);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--text);
}

@media (max-width: 720px) {
  /* Everything here is squeezed for one reason: the carousel has to be
     in the first screen ("o carrossel tem que já ser visível nesse
     primeiro momento"), and a real phone viewport is ~740px once the
     browser chrome takes its cut. Measured: this pulls the carousel's
     top from y=740 to ~y=610, so it clears the fold on a 740px screen
     instead of sitting just past it. */
  .lp-hero { padding-top: 16px; padding-bottom: 48px; }
  .lp-hero-inner { gap: 18px; }
  /* Smaller than the base clamp's 1.7rem floor, which is what a phone
     was getting (3.6vw falls under the floor at these widths). "Tem
     espaço para diminuir e continuar legível" — and the height the
     headline gives back is what pulls everything under it, carousel
     included, further up the first screen. Scales with the viewport
     again between 320px and the breakpoint instead of sitting on a
     flat floor. */
  .lp-hero-copy h1 { font-size: clamp(1.25rem, 5.5vw, 1.7rem); margin: 0 0 14px; }
  .lp-hero .hero-search-hint { margin-bottom: 20px; }
  .lp-hero-copy .section-lead { margin-bottom: 16px; }
  .lp-hero-actions { margin-top: 18px; }
  /* Painel menor no cilindro: numa tela de celular o print e uma
     miniatura de qualquer jeito, e o raio do anel e calculado a partir
     desta largura no main.js. */
  .lp-models-stage { --panel-w-max: 300px; }
  .lp-model-tag { top: 9px; left: 9px; padding: 4px 9px; font-size: 0.54rem; }
  .lp-model-info { padding: 28px 12px 11px; gap: 5px; }
  .lp-model-info h3 { font-size: 0.82rem; }
  .lp-model-metric { padding: 3px 9px; font-size: 0.66rem; }
  .lp-models-label { margin-bottom: 8px; font-size: 0.64rem; }
  .lp-models-dots { margin-top: 12px; }
  /* Everything in this row is trimmed rather than dropped, so the whole
     thing fits inside the screen with the "Criar" label intact ("a
     search bar tem que caber na tela"). */
  .lp-search-row { gap: 8px; }
  .lp-hero .hero-search { padding: 5px 5px 5px 13px; gap: 8px; }
  .lp-hero .hero-search-icon { width: 16px; height: 16px; }
  /* 16px exactly: below that, mobile browsers zoom the page in when the
     field takes focus, which is what pushed the bar off both edges of
     the screen once the keyboard opened. */
  .lp-hero .hero-search-input { font-size: 16px; padding: 10px 0; }
  .hero-search-create { padding: 10px 12px; gap: 7px; font-size: 0.85rem; }
  .hero-search-create img { width: 18px; height: 18px; }
  .lp-contact-icon { font-size: 0.66rem; gap: 3px; }
  .lp-contact-icon img { width: 32px; height: 32px; }
  .lp-pillars { grid-template-columns: 1fr; gap: 14px; }
  .lp-includes .section-lead { margin-bottom: 28px; }
  .lp-includes-close { margin-top: 32px; }
}

/* Service preview modal — a card click opens this instead of navigating
   straight off (see main.js), so the person gets a quick taste of that
   service before choosing to go further via the modal's own CTA link
   (real navigation, same tab — no target="_blank"). --accent/--accent-soft
   are copied in from whichever card triggered it, the same custom
   properties each .service-card--* modifier already sets on the card
   itself, so the preview's color always matches. */
.service-modal {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: grid;
  place-items: center;
  padding: 24px;
  visibility: hidden;
  opacity: 0;
  transition: opacity .25s ease, visibility .25s ease;
}
.service-modal.is-open { visibility: visible; opacity: 1; }
.service-modal-backdrop {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: rgba(10, 10, 12, .78);
  backdrop-filter: blur(4px);
}
/* Takeoff/speed-line effect behind the dialog ("aquele efeito de
   decolagem... linhas indicando velocidade, que alguma coisa está indo
   pra cima") — a repeating-linear-gradient standing in for hand-drawn
   motion lines, animated by sliding background-position upward. The
   gradient's stops total exactly 90px (30 transparent + 3 accent line +
   13 transparent + 1 white line + 43 transparent) and the keyframe
   travels exactly one period (-90px), so the tile wraps with zero seam —
   same trick as .hero-kicker/.btn-whatsapp's shine, just one-directional
   since "speed" reads better as a constant scroll than a ping-pong.
   ::after paints a static vignette on top (never masking — see the
   standing project rule against mask-image/mask-composite) so the lines
   read as motion concentrated behind the card instead of a flat grid
   filling the whole screen. Colored via --accent-soft, the same custom
   property the CTA button below and the card that opened this modal
   already share, so the launch color always matches that service. */
.service-modal-speedlines {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .35s ease;
  pointer-events: none;
}
.service-modal.is-open .service-modal-speedlines { opacity: 1; }
.service-modal-speedlines::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    to top,
    transparent 0 30px,
    var(--accent-soft) 30px 33px,
    transparent 33px 46px,
    rgba(255,255,255,.22) 46px 47px,
    transparent 47px 90px
  );
  animation: speedlines-rise 1.3s linear infinite;
  animation-play-state: paused;
}
.service-modal.is-open .service-modal-speedlines::before { animation-play-state: running; }
.service-modal-speedlines::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 60% 55% at 50% 55%, transparent 0%, transparent 35%, rgba(10,10,12,.55) 68%, rgba(10,10,12,.96) 100%);
}
@keyframes speedlines-rise {
  from { background-position-y: 0; }
  to   { background-position-y: -90px; }
}
.service-modal-dialog {
  position: relative;
  width: min(420px, 100%);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  overflow: hidden; /* clips .service-modal-banner's image to the
    dialog's own rounded corners once the desktop layout adds it */
  transform: translateY(14px) scale(.97);
  transition: transform .3s cubic-bezier(.22,1,.36,1);
  box-shadow: 0 30px 70px rgba(0,0,0,.5), 0 0 0 1px var(--accent-soft), 0 0 60px 8px var(--accent-soft);
}
.service-modal.is-open .service-modal-dialog { transform: translateY(0) scale(1); }
.service-modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 1.3rem;
  line-height: 1;
  border: 1px solid var(--border);
  cursor: pointer;
  transition: color .2s ease, background .2s ease;
}
.service-modal-close:hover { color: var(--text); background: var(--surface); }
/* Hidden by default (mobile keeps the pre-existing icon-only layout);
   shown as the left-column banner from 721px up — see the media query
   below. Placeholder content is the same --art illustration each
   .service-card already uses as its own background (copied over in
   main.js alongside --accent/--accent-soft) so there's a real image
   here today instead of an empty panel; swap for a dedicated banner
   asset per service once the Wendell sends the ones he's generating
   (see contexto.md). */
.service-modal-banner {
  display: none;
  position: relative;
  background-image:
    linear-gradient(180deg, transparent 40%, var(--surface) 96%),
    var(--art);
  background-size: cover;
  background-position: center;
}
/* MacBook camera-notch detail — reads the banner as "shown on a
   laptop screen" without a full device-frame illustration (no new
   image asset, just a small dark pill at the top edge). */
.service-modal-banner::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 84px;
  height: 15px;
  background: #0a0a0a;
  border-radius: 0 0 10px 10px;
  z-index: 1;
}
.service-modal-panel { padding: 40px 32px 32px; text-align: center; }
.service-modal-title { font-size: 1.3rem; margin-bottom: 10px; }
.service-modal-desc { font-size: .95rem; margin-bottom: 20px; }
/* Short highlight points distilled from the card's own description
   (see data-highlights in index.html + main.js) — built to stay
   legible in the narrow 20% desktop column: no bullet glyph (a
   colored dash via ::before instead, cheaper to align at this width
   than a real list-style marker), tight line-height, one accent-soft
   chip-style background so each point still reads as a discrete unit
   even when it wraps to 2 lines. */
.service-modal-highlights {
  list-style: none;
  margin: 0 0 22px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.service-modal-highlights li {
  position: relative;
  padding-left: 16px;
  font-size: .85rem;
  line-height: 1.35;
  color: var(--text);
}
/* Bolinha no lugar do traço. O `top` é fixo em px, não em `em`: a
   altura de linha aqui é 18,36px (0.85rem × 1.35), então centralizar
   uma bolinha de 6px na PRIMEIRA linha pede (18,36 − 6) / 2 ≈ 6px. Em
   `em` o valor escala com a fonte mas não com o tamanho da bolinha, que
   é fixo — foi exatamente isso que desalinhou as bolinhas do
   .hero-stats antes. */
.service-modal-highlights li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 6px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
/* No .btn-primary here on purpose — that class hardcodes --orange, and
   this button needs to track whichever service's card opened the modal
   (set as --accent/--accent-soft on #service-modal itself in main.js,
   inherited down to here). Declaring color/background directly avoids
   any doubt about which rule wins. */
.service-modal-cta {
  width: auto;
  max-width: 100%;
  justify-content: center;
  color: #fff;
  background: var(--accent);
  box-shadow: 0 10px 24px var(--accent-soft);
  white-space: nowrap;
  text-align: center;
}
.service-modal-cta:hover {
  background: var(--accent);
  filter: brightness(1.12);
  transform: translateY(-2px);
}
body.modal-open { overflow: hidden; }

/* Mobile: the CTA's own label ("Conhecer esse serviço →") was still
   wrapping to 3 cramped lines even after the earlier nowrap fix
   (white-space:normal above) — on a narrow phone, .service-modal's 24px
   outer padding + .service-modal-panel's 32px side padding + the
   btn-lg-sized button's own 34px side padding left barely ~175px for
   the text itself. A fully pill-shaped button (border-radius:999px)
   stretched tall by 3 lines reads as a bulging blob instead of a button
   ("aqui ainda está quebrado"). Recovers width at each layer that was
   eating into it (outer gutter, panel padding, button padding) instead
   of just one, and softens the radius so however many lines it wraps
   to, it still reads as a rounded button rather than a pill straining
   to be a circle. Scoped to mobile only — the 721px-up rules above
   already give the CTA plenty of room in the 2-column layout. */
@media (max-width: 720px) {
  .service-modal { padding: 16px; }
  .service-modal-panel { padding: 32px 22px 28px; }
  .service-modal-cta {
    padding: 12px 16px;
    font-size: .88rem;
    border-radius: 16px;
  }
  /* .service-modal-highlights is a column flex list, so each <li>
     stretches to the ul's full width by default (align-items:stretch)
     — fine on desktop where .service-modal-panel is text-align:left,
     since the li's own left edge already lines up with the text's left
     edge either way. But .service-modal-panel is text-align:center
     here on mobile, which centers the TEXT inside each still-full-
     width <li> while the ::before dash stays pinned to the li's own
     left:0 — so the dash and its text drift apart the shorter the line
     ("os indicadores de tópicos estão distantes do texto... os traços
     laranjas"). align-items:center shrinks each <li> to its own text
     width and centers THAT, so the dash (still left:0 on the now
     tightly-fit li) sits right next to its text again. */
  .service-modal-highlights { align-items: center; }
}

/* Desktop: two columns instead of the mobile single stack — banner on
   the left, text + CTA on the right, button pinned to the panel's own
   bottom edge (flex column + margin-top:auto on the CTA) regardless of
   how long the description + highlights run. 80/20 split (4fr 1fr) and
  a bigger dialog, per explicit request — the text column gets 40% of
  the dialog so its copy and CTA have room to breathe. Same 721px cutoff the rest of the
   site's mobile-vs-desktop split already uses. */
@media (min-width: 721px) {
  .service-modal-dialog {
    display: grid;
    grid-template-columns: 3fr 1.8fr;
    width: min(1020px, 94vw);
    min-height: 540px;
    max-height: 88vh;
  }
  .service-modal-banner { display: block; }
  .service-modal-panel {
    display: flex;
    flex-direction: column;
    text-align: left;
    padding: 36px 28px 28px;
    overflow-y: auto; /* safety net if a future service's copy ever
      runs taller than max-height allows — scrolls the text column
      only, the banner image never crops/scrolls */
  }
  .service-modal-cta {
    width: 100%;
    margin-top: auto;
  }
}

/* About */
.about-inner {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 56px;
  align-items: center;
}
.about-copy p { font-size: 1.02rem; }
/* Founder photo + orbiting app icons — the exact ring built for the
   hero (see the removal note on .hero-emblem above), moved here per
   explicit request once the Wendell decided where "outro lugar" was.
   --r-inner/--r-outer are declared here because .icon-orbit's calc()s
   below need them on this element specifically — same requirement the
   hero had. Enlarged 01/09 ("quero que o agrupamento pegue mais
   espaço de tela") — now close to the hero's own original scale
   (min(220px,28vw) / min(295px,38vw)) rather than the smaller
   supporting-visual size this started at. min-height grows to match
   so the taller outer ring has room without clipping. */
.about-card {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: clamp(360px, 48vw, 620px);
  --r-inner: clamp(90px, 17vw, 210px);
  --r-outer: clamp(130px, 24vw, 300px);
}
.about-photo {
  position: relative;
  z-index: 2;
  width: clamp(220px, 28vw, 370px);
  filter: drop-shadow(0 20px 40px rgba(0,0,0,.45));
}
.about-photo::before {
  content: '';
  position: absolute;
  inset: 8% 10% 10% 10%;
  background: radial-gradient(circle at 50% 34%, rgba(255, 138, 52, 0.26), rgba(140, 92, 255, 0.18) 32%, rgba(22, 120, 255, 0.08) 52%, rgba(0,0,0,0) 72%);
  filter: blur(26px);
  opacity: 0.9;
  z-index: 0;
}
.about-photo img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  display: block;
}
.icon-orbit {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.orbit-ring-wrap {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.ring-inner { width: calc(var(--r-inner) * 2); height: calc(var(--r-inner) * 2); }
.ring-outer { width: calc(var(--r-outer) * 2); height: calc(var(--r-outer) * 2); }
.orbit-ring {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  animation: orbit-spin linear infinite;
}
.ring-inner .orbit-ring { animation-duration: 32s; }
.ring-outer .orbit-ring { animation-duration: 50s; }

.orbit-icon-pos {
  position: absolute;
  top: 50%;
  left: 50%;
  width: clamp(18px, 5vw, 26px);
  height: clamp(18px, 5vw, 26px);
  margin-top: calc(clamp(18px, 5vw, 26px) / -2);
  margin-left: calc(clamp(18px, 5vw, 26px) / -2);
}
.ring-inner .orbit-icon-pos { transform: rotate(var(--angle)) translateY(calc(var(--r-inner) * -1)) rotate(calc(var(--angle) * -1)); }
.ring-outer .orbit-icon-pos { transform: rotate(var(--angle)) translateY(calc(var(--r-outer) * -1)) rotate(calc(var(--angle) * -1)); }

.orbit-icon-spin {
  display: block;
  width: 100%;
  height: 100%;
  animation: orbit-spin linear infinite reverse;
}
.ring-inner .orbit-icon-spin { animation-duration: 32s; }
.ring-outer .orbit-icon-spin { animation-duration: 50s; }

.orbit-icon-spin img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  background: rgba(255,255,255,.02);
  box-shadow: 0 0 0 1px rgba(255,255,255,.06), 0 5px 12px rgba(0,0,0,.26);
  filter: saturate(1.03) brightness(1.02) drop-shadow(0 0 1.5px var(--icon-glow, rgba(255,255,255,.12))) drop-shadow(0 0 4px var(--icon-glow, rgba(255,255,255,.08)));
  -webkit-filter: saturate(1.03) brightness(1.02) drop-shadow(0 0 1.5px var(--icon-glow, rgba(255,255,255,.12))) drop-shadow(0 0 4px var(--icon-glow, rgba(255,255,255,.08)));
  pointer-events: auto;
  transition: transform .18s ease, box-shadow .18s ease, filter .18s ease;
}

.orbit-icon-spin img:hover {
  transform: scale(1.002);
  box-shadow: 0 0 0 1px rgba(255,255,255,.08), 0 5px 12px rgba(0,0,0,.3);
  filter: saturate(1.06) brightness(1.04) drop-shadow(0 0 2.5px var(--icon-glow, rgba(255,255,255,.14))) drop-shadow(0 0 6px var(--icon-glow, rgba(255,255,255,.1)));
  -webkit-filter: saturate(1.06) brightness(1.04) drop-shadow(0 0 2.5px var(--icon-glow, rgba(255,255,255,.14))) drop-shadow(0 0 6px var(--icon-glow, rgba(255,255,255,.1)));
}

@keyframes orbit-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
/* Decorative but the motion IS the feature — keep spinning even under
   prefers-reduced-motion, don't add a media-query override (same rule
   the hero version followed). */

/* Avaliações — same centered-header pattern as .services (dash removed
   from .section-tag for the same reason: it floats disconnected once
   the tag itself is centered instead of left-aligned), card grid left-
   aligned inside like .services-grid. Copy is illustrative for now,
   written by Claude at Wendell's explicit request ("crie as
   avaliações") rather than real customer quotes — see contexto.md for
   the plan to swap in real reviews/the Google link. */
.reviews { text-align: center; }
.reviews .section-tag { padding-left: 0; }
.reviews .section-tag::before { display: none; }
.reviews .section-lead { margin: 0 auto 44px; }
/* Desktop: continuous horizontal marquee instead of a static grid
   ("um pouco mais de avaliações... elas devem passar em looping para a
   esquerda e voltar vindo pela direita, sem parar, é contínuo"). The
   9 authored cards are cloned once by main.js (desktop only, checked at
   load) and appended right after the originals, giving .reviews-grid
   exactly two back-to-back copies — animating transform from
   translateX(0) to translateX(-50%) then snapping straight back to 0%
   is seamless precisely because that -50% mark is pixel-identical to
   the start (second copy = first copy), same "duplicate the content,
   animate exactly one period" principle as .hero-kicker's shine, just
   on the X axis with real DOM nodes instead of a background position.
   .reviews-marquee (the overflow:hidden ancestor) is what "vindo pela
   direita" actually looks like — cards aren't teleporting, new ones
   are continuously scrolling in from its right edge as old ones exit
   its left. Mobile keeps its own separate stacked-deck treatment below
   (different media query, same .reviews-grid/.review-card classes,
   mutually exclusive breakpoints so there's no conflict). */
/* Breaks out of .container but stops 48px short of the window on each
   side ("preciso que acabe antes de tocar a borda da janela"), and the
   cards themselves fade out at both ends ("quero que os cards animados
   esmaeçam").
   The fade is a mask, which is normally off-limits here — the project
   banned mask-image/mask-composite after two silent production
   breakages. Wendell approved it for this one element specifically,
   and the two failures were a different animal: one was
   mask-composite, the other a radial mask over a conic-gradient. This
   is the plainest possible case (a single horizontal linear-gradient
   over a block), which is exactly the shape of mask browsers support
   best. It is also the only way to get what was asked: an overlay can
   only fake a fade by painting the page's own color over the cards,
   and with .bg-fx now rendering, that overlay reads as a flat slab
   against the glow and grain — which is the artifact this replaces.
   Keep the -webkit- prefix: Safari still needs it. */
.reviews-marquee {
  position: relative;
  overflow: hidden;
  margin-left: calc(50% - 50vw + 48px);
  margin-right: calc(50% - 50vw + 48px);
  padding: 0;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 130px, #000 calc(100% - 130px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 130px, #000 calc(100% - 130px), transparent 100%);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
}
.reviews-grid {
  display: flex;
  flex-wrap: nowrap;
  width: max-content;
  gap: 24px;
  text-align: left;
  margin-bottom: 44px;
  animation: reviews-scroll 50s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .reviews-grid { animation: none; }
}
/* Duas linhas no desktop, deslocadas entre si como tijolos ("não
   precisam estar alinhadas verticalmente, pode estar igual os desenhos
   que blocos/tijolos fazem"): meia largura de card (340 + 24 de gap,
   dividido por 2) puxa a linha de baixo pro lado, então as junções de
   uma nunca caem embaixo das da outra. A segunda linha é criada pelo
   main.js — o HTML continua com uma .reviews-grid só, senão a pilha de
   cartas do mobile passaria a montar dois baralhos. */
@media (min-width: 721px) {
  .reviews-grid { margin-bottom: 20px; }
  .reviews-grid--b { margin-left: -182px; margin-bottom: 44px; }
}
@keyframes reviews-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
/* The edge-fades that used to live here are gone (05/09). They were
   gradient overlays painting var(--bg) to soften the marquee's side
   cut ("para não ter corte seco na borda lateral"), which worked
   perfectly while the whole page was flat black — the overlay was the
   exact page color, so nobody could see it. Once .bg-fx started
   rendering (see the body-background bug), that same overlay became a
   flat, glow-less, grain-less slab sitting on top of the ambient
   background: "existe um fade visível, não há necessidade dele ser
   visível se a intenção é esconder os cards". Making the overlay match
   a textured, glowing background is exactly the job mask-image does,
   and this project doesn't use mask-image. So the fix removes the
   problem instead: the track above is full-bleed now, cards exit at
   the window edge, and there is nothing left to soften. */
.review-card {
  position: relative;
  overflow: hidden; /* clips .card-tap-light (mobile tap ripple) below to
    the card's own rounded corners */
  flex: 0 0 340px;
  width: 340px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 26px 24px;
  transition: transform .3s ease, border-color .3s ease, box-shadow .3s ease;
  /* Cards are clickable on mobile now (advances the stack), and touch
     browsers paint their own default tap-highlight (often a flat blue
     tint) on anything tappable — "quando clico marca em azul, não
     quero isso". */
  -webkit-tap-highlight-color: transparent;
}
/* :hover has no real touch equivalent, but a tap can still trigger it
   on some mobile browsers, lifting the card and painting the shadow
   below meant for a mouse cursor ("não quero a sombra que está
   aparecendo nas laterais") — gated to actual hover-capable pointers. */
/* Tap feedback (mobile only): a point of light appears exactly where the
   finger touched and fades out — "quero que onde o usuário clicar, surja
   um ponto de luz que some... identificará onde o cliente clicou". Its
   left/top are set inline by main.js from the tap's own coordinates;
   this just handles the look/fade. Created and removed by JS, so no
   media query needed here to gate it to mobile — it's simply never
   created on desktop (see main.js). */
.card-tap-light {
  position: absolute;
  width: 180px;
  height: 180px;
  margin-left: -90px;
  margin-top: -90px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,106,0,.4), rgba(255,106,0,.12) 45%, transparent 72%);
  pointer-events: none;
  z-index: 5;
  animation: card-tap-fade .55s ease-out forwards;
}
@keyframes card-tap-fade {
  from { opacity: 1; transform: scale(.4); }
  to { opacity: 0; transform: scale(1.5); }
}
@media (prefers-reduced-motion: reduce) {
  .card-tap-light { display: none; }
}
/* No hover effect on desktop reviews at all ("não precisa de nenhum
   efeito hover, somente uma animação das avaliações passando sentido
   carrossel") — the only motion here is the marquee scroll itself
   (.reviews-grid's animation, above), so this lift/border/shadow
   :hover was removed rather than kept alongside it. */
.review-stars {
  display: flex;
  gap: 3px;
  color: var(--orange);
  margin-bottom: 14px;
}
.review-stars svg { width: 16px; height: 16px; }
.review-quote {
  font-size: .95rem;
  color: var(--text);
  margin-bottom: 16px;
}
.review-author {
  font-size: .85rem;
  font-weight: 600;
  color: var(--text);
  margin: 0;
}
.review-author span {
  font-weight: 400;
  color: var(--text-muted);
}
/* Google icon sits at its own natural size next to the label — the
   .btn base class' gap:8px already spaces it from the text. */
.reviews-google-btn img { border-radius: 3px; }

/* Diferenciais */
.diferenciais .section-title { margin-bottom: 50px; }
.dif-grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
}
.dif-item {
  position: relative;
  overflow: hidden;
  --light-x: 50%;
  --light-y: 50%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 28px 22px;
}
.dif-item::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(circle 150px at var(--light-x) var(--light-y), rgba(255, 106, 0, .14), rgba(255, 106, 0, .035) 34%, transparent 72%);
  opacity: 0;
  transition: opacity .25s ease;
}
@media (hover: hover) and (pointer: fine) {
  .dif-item:hover::before { opacity: .7; }
}
.dif-item > * { position: relative; z-index: 1; }
/* Badge instead of a bare numeral ("preciso dessa parte como se fosse
   progressos") — a fixed 40px circle makes its vertical center a
   predictable 28px (card padding-top) + 20px (half the badge) = 48px
   from the card's top edge, which .dif-progress-line below relies on
   to line up with it without needing to measure anything at runtime. */
.dif-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255,106,0,.14);
  border: 2px solid var(--orange);
  color: var(--orange);
  font-weight: 800;
  font-size: 1.05rem;
  margin-bottom: 16px;
}
.dif-item h3 { font-size: 1.05rem; margin-bottom: 8px; }
.dif-item p { font-size: 0.92rem; margin: 0; }
@media (prefers-reduced-motion: reduce) {
  .dif-item::before { display: none; }
}
/* Progress line behind the row of badges — a single bar spanning the
   whole grid, positioned absolute so it drops out of grid placement
   (stays a plain sibling, doesn't take a 5th column) and painted before
   the 4 .dif-item cards in the DOM so their own opaque --surface
   background naturally covers it everywhere except the 3 gaps between
   cards, where it reads as a connecting thread linking 01->04. Gradient
   builds left-to-right for a "building progress" feel rather than a
   flat static bar. Only makes sense at the 4-in-a-row desktop layout —
   hidden once .dif-grid drops to 2 or 1 columns below (see those
   breakpoints). */
.dif-progress-line {
  position: absolute;
  left: 0;
  right: 0;
  top: 48px;
  height: 2px;
  background: linear-gradient(to right, rgba(255,106,0,.25), var(--orange));
  z-index: 0;
  pointer-events: none;
}
/* Escalating "destaque" per card — border, glow and badge fill all get
   stronger from 01 to 04, so the emphasis itself builds up the same
   way the progress line does ("faça com que todos tenham destaque,
   que conforme aumenta o passo a passo ele aumente o destaque").
   Independent of .dif-progress-line (which is desktop-only, needs a
   single row) — this works at any column count, mobile included.
   :nth-child counts .dif-progress-line as the grid's 1st child, so the
   4 real cards are the 2nd-5th, not 1st-4th. */
.dif-item:nth-child(2) { border-color: rgba(255,106,0,.14); box-shadow: 0 0 0 1px rgba(255,106,0,.05); }
.dif-item:nth-child(2) .dif-number { background: rgba(255,106,0,.14); }
.dif-item:nth-child(3) { border-color: rgba(255,106,0,.3); box-shadow: 0 0 22px 1px rgba(255,106,0,.09); }
.dif-item:nth-child(3) .dif-number { background: rgba(255,106,0,.22); }
.dif-item:nth-child(4) { border-color: rgba(255,106,0,.48); box-shadow: 0 0 28px 2px rgba(255,106,0,.14); }
.dif-item:nth-child(4) .dif-number { background: rgba(255,106,0,.32); }
.dif-item:nth-child(5) {
  border-color: var(--orange);
  box-shadow: 0 0 36px 4px rgba(255,106,0,.22), inset 0 0 0 1px rgba(255,106,0,.15);
}
.dif-item:nth-child(5) .dif-number { background: rgba(255,106,0,.45); }

/* Contact form section (landing-pages/ only for now, "no lugar dessa"
   pointing at that page's own final CTA — homepage keeps its plain
   .contact section unless asked to swap that too). Two columns on
   desktop (info+checklist+socials / the actual form), stacked on
   mobile per explicit request ("quero para mobile e desk"). The form
   has nowhere real to submit to (static site) — main.js intercepts
   submit, relies on the browser's own native required-field validation
   (nothing fires if that fails), and builds a WhatsApp message from the
   fields instead ("como prefere continuar? -> Falar pelo WhatsApp"). */
.contact-form-section { text-align: left; }
.cfs-grid {
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: 64px;
  align-items: start;
}
.cfs-heading {
  font-size: clamp(1.8rem, 3.2vw, 2.6rem);
  line-height: 1.15;
  margin: 0 0 18px;
}
.cfs-info .section-lead { margin: 0 0 32px; }
.cfs-checklist {
  list-style: none;
  margin: 0 0 36px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.cfs-checklist li { display: flex; align-items: center; gap: 12px; color: var(--text); font-size: .95rem; }
.cfs-checklist svg {
  flex-shrink: 0;
  box-sizing: content-box;
  width: 16px;
  height: 16px;
  padding: 5px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
}
.cfs-socials { display: flex; gap: 12px; }
.cfs-social-icon {
  width: 42px;
  height: 42px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  transition: border-color .2s ease, transform .2s ease;
}
.cfs-social-icon:hover { border-color: var(--accent); transform: translateY(-2px); }
.cfs-social-icon img { width: 20px; height: 20px; }

.cfs-form { display: flex; flex-direction: column; gap: 18px; }
.cfs-field { display: flex; flex-direction: column; gap: 8px; }
.cfs-field label {
  font-size: .78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-muted);
}
.cfs-required { color: var(--accent); }
.cfs-field input,
.cfs-field textarea {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  color: var(--text);
  font-family: inherit;
  font-size: .95rem;
  outline: none;
  transition: border-color .25s ease, box-shadow .25s ease;
}
.cfs-field textarea { resize: vertical; min-height: 110px; }
.cfs-field input::placeholder,
.cfs-field textarea::placeholder { color: var(--text-muted); }
.cfs-field input:focus,
.cfs-field textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.cfs-consent {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: .82rem;
  color: var(--text-muted);
  cursor: pointer;
}
.cfs-consent input {
  margin-top: 3px;
  flex-shrink: 0;
  accent-color: var(--accent);
  width: 16px;
  height: 16px;
}
.cfs-consent a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.cfs-consent a:hover { color: var(--accent); }
.cfs-submit { width: 100%; justify-content: center; }
.cfs-submit img { width: 20px; height: 20px; }

@media (max-width: 900px) {
  .cfs-grid { grid-template-columns: 1fr; gap: 44px; }
}

/* Legal pages (Termos de Serviço, Política de Privacidade) — plain
   prose, readable measure, reusing existing heading/paragraph tokens
   rather than inventing new ones. */
.legal-page {
  padding: 160px 0 100px;
}
.legal-page .container { max-width: 760px; }
.legal-page h1 { font-size: clamp(1.8rem, 3.2vw, 2.4rem); margin-bottom: 8px; }
.legal-page .legal-updated { color: var(--text-muted); font-size: .85rem; margin-bottom: 40px; }
.legal-page h2 { font-size: 1.15rem; margin: 36px 0 12px; }
.legal-page p, .legal-page li { color: var(--text-muted); font-size: .95rem; line-height: 1.7; }
.legal-page ul { padding-left: 20px; margin: 0 0 1em; }
.legal-page a { color: var(--orange); text-decoration: underline; text-underline-offset: 2px; }

/* Contact */
.contact { text-align: center; }
.contact-inner { display: flex; flex-direction: column; align-items: center; }
.contact .section-lead { margin: 0 auto 36px; }
.contact-info {
  margin-top: 28px;
  font-weight: 500;
  color: var(--text);
}
.contact-info a:hover { color: var(--orange); }
.contact-info .divider { margin: 0 14px; color: var(--text-muted); }

.footer-socials {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-bottom: 18px;
}
.footer-socials a {
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0.92;
  transition: opacity .2s ease, transform .2s ease;
}
.footer-socials a:hover {
  opacity: 1;
  transform: translateY(-1px);
}
.footer-socials img {
  width: 24px;
  height: 24px;
  display: block;
  filter: brightness(0) invert(1);
}
.footer-socials .instagram-link {
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.footer-socials .instagram-link img {
  width: 22px;
  height: 22px;
  filter: none;
  opacity: 1;
}
.footer-socials .whatsapp-link {
  width: 30px;
  height: 30px;
}

.footer-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 18px 26px;
  margin-bottom: 18px;
}
.footer-nav a {
  font-size: 0.92rem;
  color: rgba(255,255,255,0.8);
  transition: color .2s ease;
}
.footer-nav a:hover { color: var(--text); }

/* Footer */
.site-footer {
  background: transparent;
  color: var(--text-muted);
  padding: 34px 0 28px;
  border-top: none;
  transition: color .25s ease;
}
.footer-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
}
.footer-copy {
  font-size: 0.85rem;
  margin: 0;
  color: rgba(255,255,255,0.75);
}

/* WhatsApp float */
.whatsapp-float {
  position: fixed;
  right: 22px;
  bottom: 22px;
  width: 58px; height: 58px;
  background: #25D366;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  box-shadow: 0 10px 24px rgba(0,0,0,.25);
  z-index: 600;
  transition: transform .2s ease;
}
.whatsapp-float:hover { transform: scale(1.08); }
.whatsapp-float img { width: 30px; height: 30px; }

/* Instagram float — sits above the WhatsApp button, smaller ("bem
   menor"). No colored circle background like WhatsApp's: the official
   Instagram mark is already a rounded-square gradient icon filling its
   own canvas, so it's used as-is (own shape/colors preserved) rather
   than forcing it into a circle, which would crop the mark. bottom
   offset = WhatsApp's 22px + its 58px height + 12px gap = 92px. */
.instagram-float {
  position: fixed;
  right: 22px;
  bottom: 92px;
  width: 40px; height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 18px rgba(0,0,0,.25);
  border-radius: 12px;
  z-index: 600;
  transition: transform .2s ease;
}
.instagram-float:hover { transform: scale(1.08); }
.instagram-float img { width: 100%; height: 100%; display: block; }

.mobile-socials {
  display: none;
}

/* Same pattern as .mobile-socials above: base display:none so these
   mobile-only elements have a defined state even in the sliver between
   the max-width:720px and min-width:721px breakpoints below (a bare
   fractional viewport width, reachable via browser zoom or fractional
   OS display scaling, matches neither query — without a base rule they'd
   fall back to an unstyled, unhidden default block there). */
.mobile-cta-bar,
.mobile-cta-button {
  display: none;
}

/* Reveal-on-scroll (elements fading in as each section enters the
   viewport) removed — it came from the reference site sent when this
   project started, not something asked for, and cost real weight on
   scroll across a long page with everything else already running
   ("existia nesse site um efeito de ir surgindo as sessões conforme
   eu rolo a página. Isso pesa, quero remover"). The `reveal`/`reveal
   is-active` classes are still sprinkled across every page's markup —
   harmless now that nothing styles them, so left in place rather than
   editing every HTML file just to strip an inert class name. The
   matching IntersectionObserver in main.js (the actual per-element
   runtime cost) is removed too, not just this CSS. */

/* ==========================================================
   Responsive
   ========================================================== */
@media (max-width: 960px) {
  /* No min-height here anymore — .hero-emblem (the rocket) is width:
     min(680px,92vw) with a fixed aspect ratio, so on phones it renders
     far shorter than the old 460px floor, leaving a big empty gap
     above/below it inside .hero-visual (align-items:center was just
     padding out that unused space). Letting the box size to its own
     content (the rocket) closes that gap instead. */
  .hero-inner { grid-template-columns: 1fr; text-align: center; }
  /* Rocket above the text on mobile, inverted from desktop's reading
     order ("inverta a posição do foguete com o texto acima") — the
     source order (copy first, then visual) stays put in the markup for
     desktop/reader/tab order, this just repaints the visual order for
     the stacked mobile layout. */
  .hero-copy { order: 2; }
  .hero-visual { order: 1; }
  .hero-sub { margin-left: auto; margin-right: auto; }
  /* .hero-kicker gets an explicit width from main.js (matched to the
     headline's first line) — on desktop that width starts flush at
     the same left edge as the (left-aligned) headline, no centering
     needed. Here .hero-inner switches to text-align:center, so the
     headline's text is centered within its own full-width block; the
     kicker needs the same margin:auto trick .hero-sub uses above to
     center ITS narrower, explicitly-sized box to match. */
  .hero-kicker { margin-left: auto; margin-right: auto; }
  .hero-search { margin-left: auto; margin-right: auto; }
  .hero-copy .hero-search { display: flex; }
  .hero-actions { justify-content: center; }
  .hero-stats { flex-direction: column; align-items: center; text-align: center; gap: 20px; }
  .hero-stats-item { align-items: center; }
  /* pushed further right/down so the crop stays clear of the (now
     centered, stacked) hero text above it */
  .hero-earth { width: 850px; right: -420px; bottom: -280px; }
  .about-inner { grid-template-columns: 1fr; text-align: center; }
  .about-card { order: -1; }
  /* .section-tag's ::before dash is a left-prefix mark (position:
     absolute; left:0) — fine when .about-inner is left-aligned on
     desktop, but once it goes text-align:center here, "SOBRE A IDEALS"
     centers while the dash stays pinned to the container's left edge,
     floating disconnected from the text (same root cause already fixed
     for .services, which just removes the dash there — here it's moved
     below the text instead, so it survives as a small centered
     underline-style accent). */
  .about .section-tag {
    padding-left: 0;
    padding-bottom: 16px;
  }
  .about .section-tag::before {
    left: 50%;
    top: auto;
    bottom: 0;
    transform: translateX(-50%);
  }
  .services-grid { grid-template-columns: repeat(2, 1fr); }
  .dif-grid { grid-template-columns: repeat(2, 1fr); }
  .dif-progress-line { display: none; }
  .reviews-grid { grid-template-columns: repeat(2, 1fr); }

  .site-footer {
    text-align: center;
  }
  .footer-inner {
    align-items: center;
    text-align: center;
  }
}

@media (max-width: 720px) {
  .main-nav { display: none; }
  .header-cta { display: none; }
  .main-nav.is-open {
    /* Sobrescreve o align-items:center do desktop: em coluna ele deixaria
       cada item com a largura do proprio texto, e o alvo de toque
       encolheria pro tamanho da palavra. */
    align-items: stretch;
    display: flex;
    flex-direction: column;
    position: absolute;
    top: calc(100% + 10px);
    left: 18px;
    right: 18px;
    background: rgba(26, 26, 26, .97);
    padding: 8px;
    border: 1px solid rgba(255,255,255,.12);
    border-radius: 16px;
    gap: 4px;
    box-shadow: 0 18px 38px rgba(0,0,0,.38), 0 0 0 1px rgba(255,106,0,.06);
  }
  .main-nav.is-open a {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 10px 14px;
    border-radius: 10px;
    font-size: .95rem;
    font-weight: 400;
    color: var(--text-muted);
    transition: color .18s ease, background-color .18s ease, padding-left .18s ease;
  }
  .main-nav.is-open a::after { display: none; }
  .main-nav.is-open a:hover,
  .main-nav.is-open a:focus-visible {
    padding-left: 18px;
    color: var(--text);
    background: rgba(255,106,0,.1);
    outline: none;
  }

  /* No menu do celular o submenu não abre: já vem aberto, recuado e com
     um filete à esquerda marcando que aquilo pende de "Serviços". Um
     toque a menos, e some toda a lógica de abrir/fechar num menu que já
     é um painel aberto. */
  .nav-drop { flex-direction: column; align-items: stretch; }
  .nav-drop-seta { display: none; }
  .nav-drop-menu {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    min-width: 0;
    margin: 2px 0 6px 22px;
    padding: 0;
    gap: 0;
    border: none;
    border-left: 1px solid rgba(255,255,255,.14);
    border-radius: 0;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: none;
  }
  .nav-drop-menu::before { display: none; }
  .main-nav .nav-servico {
    min-height: 44px;
    padding: 8px 14px;
    border-radius: 0 10px 10px 0;
    font-size: .88rem;
  }
  .menu-toggle { display: flex; }
  .menu-toggle.is-active span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .menu-toggle.is-active span:nth-child(2) { opacity: 0; }
  .menu-toggle.is-active span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
  section { padding: 52px 0; }
  .hero-earth { width: 650px; right: -400px; bottom: -300px; opacity: .85; }
  .hero-emblem { width: clamp(280px, 84vw, 460px); }
  .hero-title-group {
    transform: translateY(-18px) scale(1.08);
    margin-bottom: 10px;
  }
  .about-card {
    min-height: clamp(290px, 82vw, 460px);
    --r-inner: clamp(80px, 28vw, 140px);
    --r-outer: clamp(110px, 38vw, 190px);
  }
  /* Floor lowered from 180px: at the old floor the photo's radius (90px)
     met or exceeded --r-inner below ~321px viewport width (--r-inner
     itself floors at 80px), making the inner-ring orbit icons overlap
     the photo on very narrow phones. 140px floor keeps the photo's
     radius (70px) safely under --r-inner's floor at every width; above
     ~333px the two formulas already converge back to the old curve. */
  .about-photo { width: clamp(140px, 42vw, 260px); }
  .services-grid { grid-template-columns: 1fr; }
  .service-card--featured { grid-column: span 1; }
  .dif-grid { grid-template-columns: 1fr; }
  /* Vertical version of the desktop connecting line, stacked instead of
     side-by-side ("pode fazer linhas que ligam o passo a passo").
     top:0/bottom:0 looks like it'd overshoot past the first/last badge,
     but it doesn't need trimming — those extra stretches (grid-top to
     1st badge, last badge to grid-bottom) fall entirely inside the
     first/last card's own opaque body, which already hides them; only
     the gap segments between cards, where there's no card to hide
     behind, actually show. left:42px lines up with the badge's own
     center (22px card padding + 20px half of the 40px badge — same
     arithmetic .dif-progress-line's desktop `top` already relies on,
     just the other axis). Also drops the per-card border/glow escalation
     for a plainer, calmer stack ("quero essa parte mais clean") — the
     badge fill still escalates (much subtler at that size) so the
     sequence still reads as building up, just without heavier cards. */
  .dif-progress-line {
    display: block;
    left: 42px;
    right: auto;
    top: 0;
    bottom: 0;
    width: 2px;
    height: auto;
    background: linear-gradient(to bottom, rgba(255,106,0,.25), var(--orange));
  }
  .dif-item:nth-child(2),
  .dif-item:nth-child(3),
  .dif-item:nth-child(4),
  .dif-item:nth-child(5) {
    border-color: var(--border);
    box-shadow: none;
  }
  /* Stacked-deck reviews on mobile ("amontuados como cartas/baralho...
     a cada 4 segundos o primeiro card vai pro final da fila e aparece
     outro"). Cards go position:absolute onto the same grid cell (an
     explicit min-height keeps the now-out-of-flow container from
     collapsing) and main.js cycles a data-stack attribute (0-5) every
     3s, or right away on a tap — only the front 3 positions get a rule
     here, anything else (data-stack 3/4/5, mid-cycle) just falls
     through to this base rule and sits invisible at the back. Pure CSS
     transition reacting to an attribute change, not a keyframe/rAF
     loop — cheap ("deve ser leve para não travar"), and the transition
     itself is what makes the motion continuous instead of a jump cut
     each cycle.
     Cards 1/2 first showed their real text at reduced opacity, which
     just meant 2-3 quotes' worth of text overlapping and blurring
     together into noise instead of reading as a stack ("precisa ficar
     evidente que tem cards atrás" was about the stack being visible,
     not about that overlap). Split card and content into two separate
     opacity values: the CARD stays fully opaque so its shape/edge
     genuinely peeks out from behind the front one, while its CONTENT
     (stars/quote/author) drops to 0 — what shows through is a blank
     card silhouette, not a second paragraph of half-readable text. */
  /* The full-bleed break-out is a desktop device (it's what lets cards
     leave at the window edge instead of mid-layout). Mobile is a
     stacked deck — nothing slides sideways, so the track stays inside
     the container where the card can keep its side margins. This reset
     is also what ended the old 402px-in-a-390px-viewport overflow the
     previous -24px bleed caused. */
  .reviews-marquee {
    margin: 0;
    padding: 0;
    /* No mask here — nothing slides sideways on the stacked deck, so
       there is no edge to fade, and a stray mask would only risk
       clipping the card. */
    -webkit-mask-image: none;
    mask-image: none;
  }
  .reviews-grid {
    display: grid;
    grid-template-columns: 1fr;
    position: relative;
    min-height: 230px;
    /* The desktop marquee's animation (base rule, .reviews-scroll)
       doesn't stop applying just because this narrower media query
       also matches — same leak that broke .hero-stats earlier. Without
       this, .reviews-grid kept sliding left by half its own (desktop)
       width, taking every absolutely-positioned card with it and
       pushing the whole stack off-screen ("sumiu os cards de
       avaliação"). width:max-content also gets reset back to auto —
       another base-rule leftover that has no meaning once this is a
       single-column grid instead of a flex row. */
    width: auto;
    animation: none;
  }
  .review-card {
    grid-column: 1;
    grid-row: 1;
    position: absolute;
    inset: 0;
    /* Base rule's width:340px/flex:0 0 340px (the desktop marquee's
       fixed card size) was never reset here — same leak as the other
       breakpoint bugs today. With both left AND right pinned to 0 by
       inset:0, an explicit width wins the conflict and the card stays
       340px wide anchored to the left instead of stretching to fill
       (and so center within) its container. */
    width: auto;
    flex: initial;
    transition: transform .7s cubic-bezier(.22,1,.36,1), opacity .5s ease;
    transform: translateY(26px) scale(.9);
    opacity: 0;
    z-index: 1;
    pointer-events: none;
    cursor: pointer;
  }
  .review-card > * { transition: opacity .35s ease; }
  .review-card:not([data-stack="0"]) > * { opacity: 0; }
  .review-card[data-stack="0"] { transform: translateY(0) scale(1); opacity: 1; z-index: 3; pointer-events: auto; }
  .review-card[data-stack="1"] { transform: translateY(16px) scale(.95); opacity: 1; z-index: 2; }
  .review-card[data-stack="2"] { transform: translateY(28px) scale(.9); opacity: 1; z-index: 1; }
  @media (prefers-reduced-motion: reduce) {
    .review-card,
    .review-card > * { transition: none; }
  }
  /* The 3 stat cards read as too much repeated bulk stacked on a phone
     screen ("acredito que caiba tudo isso em 1 retângulo só"). Merged
     into one shared card, numbers grouped in their own row up top
     ("os itens que estão em laranja no top... separe por linhas
     verticais que separam apenas os itens em laranja") and the labels
     regrouped into a bullet list below, still inside the same card
     ("abaixo dos itens... já inicia o texto que agrega essas
     informações... pode separar o texto em tópico").
     Second rebuild of this block — the first (flexbox order + wrap)
     broke two ways in a row: a flex-direction:column leaking in from
     the 960px breakpoint above (fixed once), and then
     .hero-stats-label's base rule (max-width:200px, meant for the
     desktop 3-separate-card layout) leaking through too, which combined
     with flex-wrap on a single shared flex line made both the numbers
     AND the labels wrap unpredictably ("quebrou tudo"). Explicit CSS
     Grid placement instead of flex order removes that whole class of
     bug: every item gets an exact grid-row/grid-column, so there is no
     wrapping heuristic left to go wrong regardless of what leaks in
     from another breakpoint. display:contents on .hero-stats-item still
     dissolves its own box so its border/background/::after shine don't
     render; its number+label spans become direct grid children of
     .hero-stats. Both .hero-stats-number and .hero-stats-label are
     <span> tags, so in the flattened child list (number,label,number,
     label,number,label) the numbers are always the 1st/3rd/5th <span>
     and the labels the 2nd/4th/6th — :nth-of-type(1/3/5) place the 3
     numbers in row 1's three columns, :nth-of-type(2/4/6) place the 3
     labels each on their own full-width row below. */
  .hero-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0;
    /* .hero-stats still carries the generic .container width:100% and
       its desktop padding. On mobile, adding side margins to that full
       width made the card 36px wider than the viewport. width:auto lets
       the block fill only the space left between the real side margins;
       each number/label below carries its own smaller padding. */
    width: auto;
    margin-left: 18px;
    margin-right: 18px;
    padding-left: 0;
    padding-right: 0;
    background-color: rgba(26, 26, 26, .55);
    background-image:
      radial-gradient(circle at 50% 45%, rgba(255,106,0,.18), transparent 65%),
      radial-gradient(rgba(255,255,255,.07) 1px, transparent 1.6px);
    background-size: auto, 18px 18px;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255,255,255,.12);
    border-radius: var(--radius);
    box-shadow: 0 14px 30px rgba(0,0,0,.3);
    overflow: hidden;
  }
  .hero-stats-item { display: contents; }
  .hero-stats-number {
    grid-row: 1;
    min-width: 0;
    max-width: none;
    font-size: clamp(1rem, 4.8vw, 1.25rem);
    text-align: center;
    padding: 16px 8px;
    border-right: 1px solid rgba(255,255,255,.14);
  }
  /* :nth-of-type on .hero-stats-number/-label directly doesn't work
     here — display:contents removes .hero-stats-item's own BOX, but
     the DOM tree (what :nth-of-type actually counts against) is
     unchanged: each number/label pair is still 2 children of its OWN
     .hero-stats-item parent, so ALL 3 numbers are "the 1st span within
     their own parent" and every :nth-of-type(1) rule matched all 3 at
     once — every number landed in column 1, every label in the same
     row, all overlapping ("quebrou tudo" — this was that break).
     .hero-stats-item itself is a real, unflattened DOM sibling though,
     so :nth-child on THAT (then reaching into its child span) correctly
     picks out one item at a time. */
  .hero-stats-item:nth-child(1) .hero-stats-number { grid-column: 1; }
  .hero-stats-item:nth-child(2) .hero-stats-number { grid-column: 2; }
  .hero-stats-item:nth-child(3) .hero-stats-number { grid-column: 3; border-right: none; }
  .hero-stats-label {
    grid-column: 1 / -1;
    /* Overrides the base (desktop) rule's max-width:200px — that cap
       made sense when each label lived alone inside its own card, but
       left here it capped every label at 200px regardless of this
       card's real width, which is what caused the wrap chaos above. */
    max-width: none;
    position: relative;
    text-align: left;
    font-size: .85rem;
    padding: 9px 20px 9px 34px;
  }
  .hero-stats-item:nth-child(1) .hero-stats-label { grid-row: 2; margin-top: 6px; }
  .hero-stats-item:nth-child(2) .hero-stats-label { grid-row: 3; }
  .hero-stats-item:nth-child(3) .hero-stats-label { grid-row: 4; margin-bottom: 4px; }
  .hero-stats-label::before {
    content: '';
    position: absolute;
    left: 20px;
    /* Measured against the actual rendered first line (not guessed):
       the dot sat ~8px above the text's real vertical center ("precisa
       alinhar as bolinhas com as frases, estão um pouco desalinhadas").
       16px lines the dot's own center up with the first line's. */
    top: 16px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--orange);
  }

  body {
    padding-bottom: 88px;
  }

  .mobile-socials {
    position: fixed;
    right: 12px;
    bottom: 12px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    z-index: 600;
    pointer-events: auto;
    opacity: 1;
    transform: translateY(0);
    transition: opacity .28s ease, transform .28s ease;
  }

  body.mobile-social-hidden .mobile-socials {
    opacity: 0;
    transform: translateY(18px);
    pointer-events: none;
  }

  .mobile-socials .instagram-float,
  .mobile-socials .whatsapp-float {
    position: static;
    right: auto;
    bottom: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    z-index: auto;
  }

  .mobile-socials .instagram-float {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    box-shadow: 0 8px 18px rgba(0,0,0,.25);
    background: rgba(255,255,255,0.06);
    border: 2px solid rgba(255,255,255,0.9);
    overflow: hidden;
  }

  .mobile-socials .instagram-float img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }

  .mobile-socials .whatsapp-float {
    width: 48px;
    height: 48px;
    background: linear-gradient(135deg, #1ecf65, #1ab861);
    box-shadow: 0 16px 28px rgba(26, 184, 97, 0.35);
  }

  .mobile-cta-bar {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: 22px;
    z-index: 999;
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 6px;
    pointer-events: none;
    opacity: 0;
    transform: translateY(18px);
    transition: opacity .28s ease, transform .28s ease;
  }

  body.mobile-cta-visible .mobile-cta-bar {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }

  .mobile-cta-button {
    width: calc(100% - 8px);
    pointer-events: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 22px 20px;
    border-radius: 18px;
    font-size: 0.92rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    /* Same metallic shine as .btn-whatsapp elsewhere — this override
       was a flat 2-stop gradient with no background-size/animation,
       which silently canceled the shine .btn-whatsapp already put on
       this button ("preciso do efeito metalizado no botão flutuante").
       background-size has to be repeated here for the same reason
       .btn-whatsapp:hover repeats it: the `background` shorthand resets
       background-size to its initial value whenever it's used, even
       when the new value doesn't mention it. */
    background: linear-gradient(155deg, #159149 0%, #34e07a 22%, #8dffc4 42%, #34e07a 62%, #1fae52 100%);
    background-size: 300% 100%;
    animation: kicker-shine 3s ease-in-out infinite alternate;
    text-shadow: 0 1px 4px rgba(0,0,0,.4);
    box-shadow: 0 18px 30px rgba(30, 207, 101, 0.28), inset 0 1px 0 rgba(255,255,255,.25);
    color: #fff;
    margin: 0;
  }
}

@media (min-width: 721px) {
  .mobile-cta-bar,
  .mobile-cta-button {
    display: none !important;
  }

  /* .mobile-socials is display:none by default (mobile-only wrapper) —
     without this, display:flex on its children below has no effect,
     since a display:none ancestor hides the whole subtree regardless.
     display:contents drops the wrapper's own box so the two floats fall
     back to their original always-visible fixed-position rules. */
  .mobile-socials {
    display: contents;
  }

  .whatsapp-float,
  .instagram-float {
    display: flex !important;
  }
}

/* ==========================================================
   Landing page: selo do card em destaque, botão "Ver modelos"
   e galeria dos modelos — 06/09
   ========================================================== */

/* Selo + brilho no card mais procurado. O texto é o mesmo já usado no
   .service-badge da home, de propósito: é a mesma promessa, e duas
   redações diferentes pro mesmo destaque só confundiriam. O brilho é
   box-shadow na cor do próprio card (--accent), então acompanha o
   serviço em vez de ser um laranja fixo. */
.lp-plan--featured {
  border-color: rgba(255,106,0,.34);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 0 44px -6px var(--accent-soft);
}
.lp-plan-badge {
  position: absolute;
  top: -11px;
  left: 22px;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--accent);
  color: #0b0b0d;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}
/* O card precisa de position:relative pro selo ancorar, e o selo sobe
   pra fora da borda — daí o padding-top maior neste card. */
.lp-plan { position: relative; }
.lp-plan--featured { padding-top: 32px; }

/* Botão que abre a galeria. No desktop ele só aparece quando o mouse
   entra no carrossel ("quando o mouse passar em cima"); no toque não
   existe hover, então fica sempre visível — senão a galeria ficaria
   inalcançável no celular. */
.lp-models-open {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(.94);
  z-index: 20;
  padding: 13px 26px;
  border: 1px solid rgba(255,255,255,.22);
  border-radius: 999px;
  background: rgba(10,10,12,.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--text);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 700;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease, transform .25s ease, background .25s ease;
  -webkit-tap-highlight-color: transparent;
}
.lp-models { position: relative; }
@media (hover: hover) and (pointer: fine) {
  .lp-models:hover .lp-models-open {
    opacity: 1;
    pointer-events: auto;
    transform: translate(-50%, -50%) scale(1);
  }
  .lp-models-open:hover { background: rgba(255,106,0,.9); border-color: transparent; color: #0b0b0d; }
}
@media (hover: none), (pointer: coarse) {
  .lp-models-open {
    position: static;
    display: block;
    margin: 18px auto 0;
    transform: none;
    opacity: 1;
    pointer-events: auto;
    font-size: 0.82rem;
    padding: 10px 20px;
  }
}

/* Galeria: uma olhada rápida em todos os modelos de uma vez, já que no
   carrossel eles passam. Fecha no X, no Esc e clicando no fundo. */
.lp-gallery {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(8,8,10,.86);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  visibility: hidden;
  opacity: 0;
  transition: opacity .25s ease, visibility .25s ease;
}
.lp-gallery.is-open { visibility: visible; opacity: 1; }
.lp-gallery-panel {
  position: relative;
  width: min(1040px, 100%);
  max-height: 86vh;
  overflow-y: auto;
  padding: 28px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}
.lp-gallery-title { margin: 0 0 4px; font-size: 1.15rem; }
.lp-gallery-lead { margin: 0 0 22px; font-size: 0.9rem; }
.lp-gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
}
.lp-gallery-item {
  position: relative;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.08);
  background: var(--bg);
}
.lp-gallery-item img { width: 100%; height: auto; display: block; }
.lp-gallery-close {
  position: absolute;
  top: 12px;
  right: 14px;
  width: 34px;
  height: 34px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Filtros por categoria da galeria + visualizador em tamanho grande */
.lp-gallery-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 20px;
}
.lp-gallery-filter {
  padding: 7px 15px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(255,255,255,.03);
  color: var(--text-muted);
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
  -webkit-tap-highlight-color: transparent;
}
.lp-gallery-filter[aria-pressed="true"] {
  background: var(--orange);
  border-color: transparent;
  color: #0b0b0d;
}
@media (hover: hover) and (pointer: fine) {
  .lp-gallery-filter:not([aria-pressed="true"]):hover { color: var(--text); border-color: rgba(255,255,255,.25); }
}
/* O item da grade virou <button> pra abrir o projeto — reset do que o
   navegador põe em botão, senão herda fundo e borda próprios. */
.lp-gallery-item {
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .25s ease, border-color .25s ease;
}
@media (hover: hover) and (pointer: fine) {
  .lp-gallery-item:hover { transform: translateY(-3px); border-color: rgba(255,106,0,.4); }
}
.lp-gallery-viewer {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  padding: 16px 24px;
  background: rgba(6,6,8,.94);
  overflow-y: auto;
  overscroll-behavior: contain;
  visibility: hidden;
  opacity: 0;
  transition: opacity .2s ease, visibility .2s ease;
}
.lp-gallery-viewer.is-open { visibility: visible; opacity: 1; }

/* Título de cada card de preço com o metalizado na cor do próprio card.
   Aqui as rampas são escritas uma a uma, e não geradas a partir de
   --accent com color-mix(): se color-mix não for suportado, a parada do
   gradiente inteira é inválida e, com background-clip:text +
   text-fill-color:transparent, o título simplesmente SOME. São quatro
   cards; quatro rampas explícitas é mais barato que esse risco. As de
   laranja e verde são as mesmas de .text-shine-orange/.text-shine-green,
   pra não existirem dois laranjas metálicos diferentes no site. */
.lp-plan h3 {
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
.lp-plan--orange h3 { background-image: linear-gradient(95deg, #7a3300 0%, #e25400 18%, #ff9a3d 40%, #fff2e0 50%, #ff9a3d 60%, #e25400 82%, #7a3300 100%); }
.lp-plan--cyan   h3 { background-image: linear-gradient(95deg, #0e4d57 0%, #1aa8bf 18%, #7ee8f7 40%, #e9feff 50%, #7ee8f7 60%, #1aa8bf 82%, #0e4d57 100%); }
.lp-plan--green  h3 { background-image: linear-gradient(95deg, #0e5c34 0%, #1fae52 18%, #6dffb0 40%, #eafff2 50%, #6dffb0 60%, #1fae52 82%, #0e5c34 100%); }
.lp-plan--purple h3 { background-image: linear-gradient(95deg, #3d1f73 0%, #7c3fd6 18%, #c4a2ff 40%, #f3ebff 50%, #c4a2ff 60%, #7c3fd6 82%, #3d1f73 100%); }
@media (prefers-reduced-motion: reduce) {
  .lp-plan h3 { animation: none; }
}

/* Botão "abrir o site" no canto do card da galeria e dentro do
   visualizador. Renderizado só quando o projeto tem data-url — ver
   main.js. */
.lp-model-visit {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(10,10,12,.78);
  border: 1px solid rgba(255,255,255,.2);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: var(--text);
  font-size: 0.85rem;
  line-height: 1;
  transition: background .2s ease, border-color .2s ease, transform .2s ease;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .lp-model-visit:hover { background: var(--orange); border-color: transparent; color: #0b0b0d; transform: scale(1.08); }
}
/* Dentro do visualizador ele vira um botão com rótulo, abaixo da
   imagem: ali há espaço e o clique é a próxima ação natural. */
.lp-model-visit--viewer {
  position: static;
  /* flex + width:fit-content pra que o margin:auto centralize de fato —
     em inline-flex a margem automática não centraliza. */
  display: flex;
  width: fit-content;
  height: auto;
  margin: 14px auto 0;
  padding: 10px 20px;
  border-radius: 999px;
  gap: 8px;
  font-size: 0.86rem;
  font-weight: 700;
  background: var(--orange);
  border-color: transparent;
  color: #0b0b0d;
}

/* Escurece os painéis enquanto o mouse está sobre o carrossel, pra que o
   botão "Ver modelos" não fique flutuando por cima de um print claro e
   sumindo nele. Usa filter, não opacity: a opacidade é animada pelo
   @keyframes models-arc (é ela que faz o painel entrar e sair nas
   pontas), e mexer nela aqui brigaria com a animação. Só em ponteiro
   com hover — no toque não existe esse estado. */
@media (hover: hover) and (pointer: fine) {
  .lp-model { transition: filter .3s ease; }
  .lp-models:hover .lp-model { filter: brightness(.42) saturate(.9); }
}

/* Conteúdo textual da aba lateral do visualizador. */
.lp-gallery-viewer-tag {
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.16);
  background: rgba(255,255,255,.06);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--orange);
}
.lp-gallery-viewer-name { font-size: 1.05rem; font-weight: 700; }
.lp-gallery-viewer-intent {
  font-size: 0.88rem;
  font-weight: 300;
  line-height: 1.55;
  color: var(--text-muted);
}
/* Tabela comparativa no espaço vago ao lado do formulário. Só no
   desktop, como pedido — numa coluna de celular ela viraria uma
   grade de 4 colunas espremida, ilegível. */
.lp-compare { display: none; }
@media (min-width: 981px) {
  .lp-compare { display: block; margin-top: 34px; }
}
.lp-compare-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.78rem;
  text-align: left;
}
.lp-compare-caption {
  margin-bottom: 12px;
  text-align: left;
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.lp-compare-table th,
.lp-compare-table td {
  padding: 9px 10px;
  border-bottom: 1px solid rgba(255,255,255,.07);
}
.lp-compare-table thead th {
  font-size: 0.72rem;
  border-bottom: 1px solid rgba(255,255,255,.14);
}
.lp-compare-table tbody th {
  font-weight: 400;
  color: var(--text-muted);
}
.lp-compare-table td { text-align: center; width: 84px; }
.lp-compare-col--orange { color: var(--orange); }
.lp-compare-col--cyan { color: #22d3ee; }
.lp-compare-col--green { color: #22c55e; }
.lp-compare-yes { color: #22c55e; font-weight: 700; }
.lp-compare-no { color: rgba(255,255,255,.22); }
.lp-compare-price th,
.lp-compare-price td {
  border-bottom: none;
  padding-top: 13px;
  font-weight: 800;
}
/* Preço em verde: é a informação que a pessoa veio buscar na tabela, e
   verde é a cor que o site já usa pra "pode seguir". */
.lp-compare-price td { color: #22c55e; }
.lp-compare-price th { color: var(--text-muted); font-weight: 700; }

/* Carrossel de modelos no MOBILE: baralho, não o arco do desktop.
   Segue o modelo enviado — a carta da frente inteira e as de trás
   espiando pelos lados, levemente giradas e escurecidas. O JS só troca
   o data-stack (ver main.js); cada posição da pilha está descrita aqui,
   então o movimento é transição de CSS, não animação por frame — mesma
   mecânica do baralho das avaliações. */
@media (max-width: 720px) {
  .lp-models-stage {
    /* Carta maior que no arco: aqui ela é o assunto, não uma de cinco
       passando. E o palco ganha folga lateral pras cartas de trás
       aparecerem sem serem cortadas. */
    --panel-w-frac: .74;
    --panel-w-max: 320px;
  }
  .lp-model {
    /* Desliga a animação do arco: no baralho quem manda é o data-stack. */
    animation: none;
    transition: transform .55s cubic-bezier(.22,1,.36,1), opacity .45s ease, filter .45s ease;
    transform: scale(.86);
    opacity: 0;
    pointer-events: none;
    z-index: 1;
  }
  .lp-model[data-stack="0"] {
    transform: translateX(0) scale(1) rotate(0deg);
    opacity: 1;
    filter: none;
    z-index: 4;
    pointer-events: auto;
    cursor: pointer;
  }
  .lp-model[data-stack="1"] {
    transform: translateX(15%) scale(.9) rotate(3.5deg);
    opacity: 1;
    filter: brightness(.42) saturate(.85);
    z-index: 3;
  }
  .lp-model[data-stack="2"] {
    transform: translateX(-15%) scale(.9) rotate(-3.5deg);
    opacity: 1;
    filter: brightness(.32) saturate(.8);
    z-index: 2;
  }
  /* Da terceira carta pra trás fica tudo escondido atrás da pilha, senão
     cinco projetos viram uma bagunça de bordas assomando. */
  .lp-model[data-stack="3"],
  .lp-model[data-stack="4"],
  .lp-model[data-stack="5"] {
    transform: scale(.84);
    opacity: 0;
  }
  /* Só a carta da frente mostra legenda: as de trás sobrepostas
     empilhariam textos ilegíveis. */
  .lp-model:not([data-stack="0"]) .lp-model-tag,
  .lp-model:not([data-stack="0"]) .lp-model-info { opacity: 0; }
}

/* Visualizador dos modelos como uma janela de navegador cenográfica.
   Barra, imagem e informações pertencem à mesma moldura; no desktop a
   mídia e a aba lateral dividem a mesma linha do grid, então terminam
   sempre na mesma altura sem esticar ou recortar a imagem. */
.lp-gallery-viewer-fig {
  --viewer-info-width: clamp(250px, 21vw, 290px);
  width: min(1240px, 94vw);
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--viewer-info-width);
  grid-template-rows: auto auto;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.14);
  border-radius: 16px;
  background: #0c0c0f;
  box-shadow: 0 30px 90px rgba(0,0,0,.62), 0 0 0 1px rgba(255,255,255,.025);
  transform: translateY(10px) scale(.985);
  transition: transform .28s cubic-bezier(.22,1,.36,1);
}
.lp-gallery-viewer.is-open .lp-gallery-viewer-fig { transform: translateY(0) scale(1); }

/* Em telas desktop muito baixas, a largura acompanha a altura útil para
   a janela inteira continuar visível. 208.333dvh é a proporção média
   (1400/672) das imagens dos modelos. */
@supports (height: 1dvh) {
  .lp-gallery-viewer-fig { width: min(1240px, 94vw, calc(208.333dvh + 25px)); }
}

.lp-gallery-browser {
  grid-column: 1 / -1;
  grid-row: 1;
  min-width: 0;
  color: rgba(255,255,255,.72);
  background: linear-gradient(180deg, #242429 0%, #17171b 100%);
  border-bottom: 1px solid rgba(255,255,255,.1);
  user-select: none;
}
.lp-gallery-browser-tabs {
  min-height: 38px;
  display: grid;
  grid-template-columns: auto minmax(150px, 300px) 26px 1fr;
  align-items: end;
  gap: 9px;
  padding: 7px 10px 0;
}
.lp-gallery-browser-dots {
  align-self: center;
  display: inline-flex;
  gap: 5px;
  padding: 0 2px;
}
.lp-gallery-browser-dots span {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #ff6259;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.18);
}
.lp-gallery-browser-dots span:nth-child(2) { background: #ffbd2e; }
.lp-gallery-browser-dots span:nth-child(3) { background: #28c840; }
.lp-gallery-browser-tab {
  position: relative;
  top: 1px;
  min-width: 0;
  min-height: 31px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 5px 0 11px;
  border: 1px solid rgba(255,255,255,.1);
  border-bottom-color: #111114;
  border-radius: 9px 9px 0 0;
  background: #111114;
}
.lp-gallery-browser-favicon {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 3px;
  background: var(--orange);
  box-shadow: 0 0 10px rgba(255,106,0,.55);
  transform: rotate(45deg);
}
.lp-gallery-browser-tab-title {
  min-width: 0;
  overflow: hidden;
  color: rgba(255,255,255,.86);
  font-size: .7rem;
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-gallery-browser-new-tab {
  align-self: center;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  font-size: 1rem;
  color: rgba(255,255,255,.55);
}
.lp-gallery-browser-toolbar {
  min-height: 40px;
  display: grid;
  grid-template-columns: 22px 22px 22px minmax(100px, 1fr) 22px;
  align-items: center;
  gap: 7px;
  padding: 6px 10px;
  background: #111114;
}
.lp-gallery-browser-nav,
.lp-gallery-browser-menu {
  display: grid;
  place-items: center;
  color: rgba(255,255,255,.48);
  font-size: .78rem;
}
.lp-gallery-browser-address {
  min-width: 0;
  height: 27px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 999px;
  background: #09090c;
}
.lp-gallery-browser-address-status {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--orange);
  box-shadow: 0 0 8px rgba(255,106,0,.48);
}
.lp-gallery-browser-address-text {
  min-width: 0;
  overflow: hidden;
  color: rgba(255,255,255,.47);
  font-size: .65rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lp-gallery-viewer-close {
  flex: 0 0 auto;
  width: 27px;
  height: 27px;
  margin-left: auto;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: rgba(255,255,255,.62);
  font-family: inherit;
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  transition: color .18s ease, background-color .18s ease;
  -webkit-tap-highlight-color: transparent;
}
.lp-gallery-viewer-close:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: -2px;
}
@media (hover: hover) and (pointer: fine) {
  .lp-gallery-viewer-close:hover { color: #fff; background: rgba(255,255,255,.1); }
}

.lp-gallery-viewer-media {
  grid-column: 1;
  grid-row: 2;
  min-width: 0;
  min-height: 0;
  aspect-ratio: 1400 / 672;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: #f2f2f5;
}
.lp-gallery-viewer-media img {
  width: 100%;
  height: 100%;
  max-height: none;
  display: block;
  object-fit: contain;
  border: 0;
  border-radius: 0;
}
.lp-gallery-viewer-fig figcaption {
  grid-column: 2;
  grid-row: 2;
  min-width: 0;
  min-height: 0;
  max-width: none;
  margin: 0;
  padding: 26px 24px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  overflow-y: auto;
  text-align: left;
  font-weight: 400;
  border: 0;
  border-left: 1px solid rgba(255,255,255,.1);
  border-radius: 0;
  background:
    radial-gradient(circle at 80% 0%, rgba(255,106,0,.09), transparent 42%),
    var(--surface);
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,.2) transparent;
}
.lp-gallery-viewer-fig .lp-model-visit--viewer { margin: auto 0 0; }

/* Em telas estreitas a aba passa para baixo da imagem, mas continua
   dentro da mesma janela e sem qualquer espaço entre as partes. */
@media (max-width: 860px) {
  .lp-gallery-viewer {
    place-items: start center;
    padding: 12px;
  }
  .lp-gallery-viewer-fig {
    width: min(680px, 100%);
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    margin: auto 0;
  }
  .lp-gallery-browser { grid-column: 1; }
  .lp-gallery-viewer-media {
    grid-column: 1;
    grid-row: 2;
    width: 100%;
    aspect-ratio: 1400 / 672;
  }
  .lp-gallery-viewer-fig figcaption {
    grid-column: 1;
    grid-row: 3;
    max-height: none;
    overflow: visible;
    padding: 20px;
    border-left: 0;
    border-top: 1px solid rgba(255,255,255,.1);
  }
  .lp-gallery-viewer-fig .lp-model-visit--viewer { margin-top: 8px; }
}
@media (max-width: 480px) {
  .lp-gallery-browser-tabs {
    min-height: 42px;
    grid-template-columns: auto minmax(0, 1fr) 24px;
    padding: 7px 8px 0;
  }
  .lp-gallery-browser-tabs::after { content: none; }
  .lp-gallery-browser-toolbar {
    grid-template-columns: 22px 22px minmax(80px, 1fr) 22px;
    padding-inline: 8px;
  }
  .lp-gallery-browser-nav:nth-child(2) { display: none; }
  .lp-gallery-browser-new-tab { grid-column: 3; }
  .lp-gallery-viewer-fig figcaption { padding: 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .lp-gallery-viewer-fig { transition: none; }
}

/* Card triplo (Criativos + Vídeo + Tráfego Pago). Ele junta serviços de
   duas cores, então em vez de escolher uma, o card atravessa do roxo
   dos Criativos (esquerda) ao amarelo do Tráfego Pago (direita) — no
   fundo, no título e no botão. Os elementos pontuais (ícone, tagline,
   marcadores) seguem no roxo via --accent: pintar cada um de uma cor
   deixaria o card manchado em vez de degradê.
   Um pouco mais largo que os outros três, como pedido, mas sem virar
   outra coisa: 1.3 de crescimento contra 1 dos demais. */
.lp-plan--duo {
  --accent: #9b5fff;
  --accent-soft: rgba(155,95,255,.18);
  --accent-2: #f5b942;
  --accent-2-soft: rgba(245,185,66,.2);
  flex-grow: 1.3;
  max-width: 320px;
  border-color: rgba(155,95,255,.24);
  background-image:
    radial-gradient(120% 85% at 50% -12%, var(--accent-soft), transparent 62%),
    linear-gradient(100deg, transparent 42%, var(--accent-2-soft) 100%),
    radial-gradient(rgba(255,255,255,.05) 1px, transparent 1.5px);
  background-size: auto, auto, 16px 16px;
}
/* Título metalizado atravessando as duas cores: roxo → claro → amarelo. */
.lp-plan--duo h3 {
  background-image: linear-gradient(95deg, #3d1f73 0%, #7c3fd6 18%, #c4a2ff 36%, #fff3dd 52%, #f5d488 70%, #f5b942 86%, #8a6410 100%);
}
/* Botão: a mesma camada de brilho dos outros, mas sobre uma base em
   degradê em vez de cor sólida. Duas camadas de background-image, então
   background-size precisa de dois valores — só a do brilho é que tem
   300% pra correr. */
.lp-plan--duo .lp-plan-cta {
  background-color: transparent;
  background-image:
    linear-gradient(115deg, rgba(0,0,0,.28) 0%, rgba(255,255,255,.10) 20%, rgba(255,255,255,.55) 40%, rgba(255,255,255,.10) 60%, rgba(0,0,0,.28) 100%),
    linear-gradient(100deg, #9b5fff 0%, #b98ae8 45%, #f5b942 100%);
  background-size: 300% 100%, 100% 100%;
}

/* O card triplo também leva selo, como o de Landing Page. Diferença: o
   dele acompanha o degradê roxo→amarelo do card em vez de uma cor
   chapada, senão o selo brigaria com o próprio card. Precisa de
   padding-top igual ao outro destacado, porque o selo sobe pra fora da
   borda. */
.lp-plan--duo { padding-top: 32px; }
.lp-plan--duo .lp-plan-badge {
  background-image: linear-gradient(100deg, #9b5fff 0%, #b98ae8 45%, #f5b942 100%);
}

/* Textura nos cards dos pilares e das avaliações — mesma receita já
   aprovada nos cards de preço: brilho da cor de destaque sangrando da
   borda de cima, a trama de pontinhos do .bg-fx por cima, e um fio de
   luz na borda superior. Sem isso eles eram retângulos chapados no meio
   de uma página que tem textura em todo o resto. */
.lp-pillar {
  background-color: var(--surface);
  background-image:
    radial-gradient(120% 90% at 50% -14%, var(--accent-soft), transparent 60%),
    radial-gradient(rgba(255,255,255,.05) 1px, transparent 1.5px);
  background-size: auto, 16px 16px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07);
  transition: border-color .3s ease, transform .3s ease;
}
/* O card largo recebe o brilho de um ponto mais à esquerda: centralizado
   numa caixa dessa largura, ele virava um halo genérico no meio. */
.lp-pillar--wide {
  background-image:
    radial-gradient(70% 130% at 18% -10%, var(--accent-soft), transparent 62%),
    radial-gradient(rgba(255,255,255,.05) 1px, transparent 1.5px);
}
@media (hover: hover) and (pointer: fine) {
  .lp-pillar:hover { border-color: rgba(255,106,0,.3); transform: translateY(-3px); }
}

.review-card {
  background-color: var(--surface);
  background-image:
    radial-gradient(110% 80% at 50% -12%, rgba(255,106,0,.13), transparent 62%),
    radial-gradient(rgba(255,255,255,.045) 1px, transparent 1.5px);
  background-size: auto, 16px 16px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
}

/* ==========================================================
   /criativos/ — 06/09
   ========================================================== */

/* Metalizado roxo: as classes .text-shine-* são rampas fixas por cor, e
   esta página tem roxo como cor do serviço. Mesma mecânica das outras
   (background-clip:text + kicker-shine), rampa escrita à mão pelo mesmo
   motivo dos títulos dos cards de preço — color-mix() que falha derruba
   o texto inteiro. */
.text-shine-purple {
  background: linear-gradient(95deg, #3d1f73 0%, #7c3fd6 18%, #c4a2ff 40%, #f3ebff 50%, #c4a2ff 60%, #7c3fd6 82%, #3d1f73 100%);
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 0 18px rgba(155,95,255,.4);
}
@media (prefers-reduced-motion: reduce) {
  .text-shine-purple { animation: none; }
}

/* --- Gerenciamento de perfil (/criativos/) -------------------------- */
/* Entrou no lugar do bento de categorias em 07/09. A seção não lista o
   que a gente cria: ela mostra um PERFIL, que é o que o cliente compra
   aqui. Por isso o quadro imita a página de perfil do Instagram, com
   avatar de anel, arroba, bio e a grade de três colunas. */
.cr-perfil { text-align: center; }
.cr-perfil .section-tag { padding-left: 0; }
.cr-perfil .section-tag::before { display: none; }
.cr-perfil .section-lead { max-width: 640px; margin-left: auto; margin-right: auto; }

.cr-perfil-quadro {
  max-width: 880px;
  margin: 34px auto 0;
  padding: 22px;
  text-align: left;
  border-radius: 20px;
  border: 1px solid rgba(255,255,255,.10);
  background:
    radial-gradient(90% 70% at 0% 0%, rgba(155,95,255,.14), transparent 60%),
    radial-gradient(80% 70% at 100% 100%, rgba(255,106,0,.10), transparent 62%),
    rgba(255,255,255,.03);
  box-shadow: 0 22px 50px rgba(0,0,0,.34);
}

.cr-perfil-topo {
  display: flex;
  align-items: center;
  gap: 16px;
  padding-bottom: 18px;
  border-bottom: 1px solid rgba(255,255,255,.08);
}
/* O anel em degradê é o que faz o avatar ler como perfil, e é a mesma
   receita das bolinhas de destaque: padding + fundo no pai, miolo
   escuro por cima. */
.cr-perfil-avatar {
  flex: none;
  display: block;
  width: 78px;
  height: 78px;
  padding: 3px;
  border-radius: 50%;
  background: linear-gradient(140deg, #FF6A00, #ffb36b 45%, #9b5fff);
}
.cr-perfil-avatar img {
  width: 100%;
  height: 100%;
  padding: 14px;
  border-radius: 50%;
  background: #16121d;
  object-fit: contain;
}
.cr-perfil-arroba {
  margin: 0 0 4px;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
}
/* NENHUM número aqui de propósito: seguidores e posts seriam invenção
   sobre uma conta real. O que a seção promete é o visual, não métrica. */
.cr-perfil-bio {
  margin: 0;
  font-size: .86rem;
  line-height: 1.5;
  color: var(--text-muted);
}

/* Grade de três colunas, como o Instagram mostra o próprio perfil.
   Nasce escondida: sem post, o JS não a revela e o lugar fica com a
   lista do que entra no serviço. */
.cr-perfil-grade {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  margin: 18px 0 0;
}
.cr-perfil-grade[hidden] { display: none; }
.cr-post { margin: 0; aspect-ratio: 1 / 1; overflow: hidden; border-radius: 4px; }
.cr-post img { width: 100%; height: 100%; object-fit: cover; display: block; }

.cr-perfil-inclui {
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 10px;
}
.cr-perfil-inclui li {
  position: relative;
  padding-left: 22px;
  font-size: .9rem;
  line-height: 1.5;
  color: var(--text-muted);
}
/* Bolinha em px, não em em: o ponto tem tamanho fixo, e um deslocamento
   em em escalaria com a fonte e sairia do meio da primeira linha. */
.cr-perfil-inclui li::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 9px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent, #9b5fff);
}

.cr-perfil-acao { margin-top: 30px; }

@media (max-width: 720px) {
  .cr-perfil-quadro { padding: 16px; border-radius: 16px; }
  .cr-perfil-topo { gap: 12px; }
  .cr-perfil-avatar { width: 62px; height: 62px; }
  .cr-perfil-avatar img { padding: 10px; }
  .cr-perfil-arroba { font-size: .92rem; }
  .cr-perfil-bio { font-size: .8rem; }
  .cr-perfil-inclui li { font-size: .84rem; }
  .cr-perfil-acao .btn { width: 100%; justify-content: center; }
}

/* Prévia do feed: o print entre o quadro do perfil e o CTA. É um botão
   de verdade (não uma <img> com onclick) pra funcionar no teclado e
   anunciar que abre alguma coisa. */
.cr-feed-previa { margin: 26px auto 0; max-width: 560px; }
.cr-feed-print {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  overflow: hidden;
  border-radius: 16px;
  border: 1px solid rgba(255,255,255,.12);
  background: rgba(255,255,255,.03);
  box-shadow: 0 22px 46px rgba(0,0,0,.4);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .2s ease, transform .2s ease;
}
.cr-feed-print img { display: block; width: 100%; height: auto; }

/* O selo fica SEMPRE visível, não só no hover: em tela de toque não
   existe passar o mouse, e ele é o que avisa que o print abre a
   galeria. No mouse ele só acende um pouco mais. */
.cr-feed-selo {
  position: absolute;
  right: 12px;
  bottom: 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 15px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.18);
  background: rgba(12,10,18,.82);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-size: .78rem;
  font-weight: 700;
  color: #fff;
  transition: background-color .2s ease;
}
@media (hover: hover) and (pointer: fine) {
  .cr-feed-print:hover { border-color: rgba(155,95,255,.45); transform: translateY(-2px); }
  .cr-feed-print:hover .cr-feed-selo { background: rgba(155,95,255,.9); }
}
.cr-feed-print:focus-visible { outline: 2px solid var(--accent, #9b5fff); outline-offset: 3px; }

/* Sem peça na galeria o print continua aparecendo, mas deixa de se
   oferecer como botão: some o selo e o cursor volta ao normal. */
.cr-feed-print.is-so-imagem { cursor: default; }
.cr-feed-print.is-so-imagem .cr-feed-selo { display: none; }

@media (max-width: 720px) {
  .cr-feed-previa { margin-top: 20px; }
  .cr-feed-print { border-radius: 12px; }
  .cr-feed-selo { right: 8px; bottom: 8px; padding: 8px 12px; font-size: .72rem; }
}

/* O metalizado da marca: roxo e laranja na mesma rampa, como ele pediu.
   As duas cores da página andam juntas aqui em vez de escolher uma.
   Rampa escrita à mão, como todas as outras — color-mix() invalidaria o
   gradiente inteiro onde não houvesse suporte e, com o preenchimento
   transparente, a palavra sumiria. */
.text-shine-marca {
  background-image: linear-gradient(95deg, #7c3fd6 0%, #b48cff 22%, #ffe0c6 44%, #ffffff 52%, #ffb27a 62%, #FF6A00 82%, #b0470a 100%);
  background-size: 300% 100%;
  animation: kicker-shine 3s ease-in-out infinite alternate;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 0 18px rgba(155,95,255,.32);
}
@media (prefers-reduced-motion: reduce) {
  .text-shine-marca { animation: none; }
}

/* Galeria de peças da /criativos/ — estado vazio incluído. */
.cr-galeria { text-align: center; }
.cr-galeria .section-tag { padding-left: 0; }
.cr-galeria .section-tag::before { display: none; }
/* NAO usar display:none aqui: o atributo hidden ja cuida do estado vazio,
   e um display fixo anularia o hidden=false que o JS faz quando as pecas
   chegam — elas ficariam invisiveis e o defeito so apareceria no dia do
   upload. Quando tem peca, este e o grid visivel da secao; o botao abre
   a versao filtravel por cima. */
.cr-galeria-fonte {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
  margin-top: 36px;
  text-align: left;
}
.cr-peca {
  position: relative;
  overflow: hidden;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
}
.cr-peca img { width: 100%; height: auto; display: block; }
.cr-galeria-vazia { margin: 28px 0 0; font-size: .92rem; color: var(--text-muted); }
.cr-galeria-open {
  margin-top: 28px;
  background: var(--accent);
  color: #0b0b0d;
  box-shadow: 0 14px 30px rgba(155,95,255,.28);
}

/* --- Hero da /criativos/: demonstração em vez de descrição ---------- */
/* Sem respiro embaixo: a peça sangra até o rodapé da seção e os últimos
   ~25% dela já são o esmaecimento, que faz o papel do espaçamento. Um
   padding aqui viraria faixa vazia entre a arte e a seção seguinte. */
.cr-hero { padding-top: 48px; padding-bottom: 0; }
/* Coluna unica centralizada: o titulo precisa caber em UMA linha, e numa
   grade de duas colunas ele teria ~532px, onde a frase nao entra em
   nenhum tamanho legivel. Centralizado e em largura cheia, cabe. */
.cr-hero-inner {
  /* Acima da peça: ela sobe por trás do texto com a margem negativa, e
     sem isto o botão ficaria por baixo dela. */
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* Colado no CTA de proposito: o PNG do hero tem ~6% de faixa
     transparente em cima, entao um gap normal aqui viraria o dobro de
     vao na tela. */
  gap: 10px;
}
.cr-hero h1 {
  font-size: clamp(1.5rem, 3.1vw, 2.2rem);
  margin: 0 0 14px;
}
/* Uma linha so onde ela CABE. Abaixo de 901px a frase mede mais que a
   tela (551px num viewport de 390) e o nowrap a cortava nas duas pontas
   — sem barra de rolagem aparecer, porque o html tem overflow-x:hidden,
   entao o defeito passava despercebido. */
@media (min-width: 901px) {
  .cr-hero h1 { white-space: nowrap; }
}
.cr-hero .section-lead { max-width: 620px; margin: 0 auto 28px; }
/* Uma linha so a partir de 901px, mesma regra do titulo: abaixo disso a
   frase mede mais que a tela e o nowrap a cortaria em silencio, porque o
   html tem overflow-x:hidden. */
@media (min-width: 901px) {
  .cr-hero .section-lead { max-width: none; white-space: nowrap; }
}
.cr-hero-copy { display: flex; flex-direction: column; align-items: center; }
/* A peça do hero. Uma imagem só, recortada e com o brilho embutido —
   nada de moldura, borda ou sombra de caixa aqui: o PNG já traz tudo
   isso e um retângulo em volta brigaria com o recorte. Mais larga que a
   coluna de texto de propósito, como ele mostrou na referência. */
.cr-demo {
  position: relative;
  /* Cria contexto de empilhamento próprio: sem ele o ::before com
     z-index:-1 disputaria camada com o .bg-fx do fundo do site, que
     também é -1. Com o isolate, o brilho fica preso aqui dentro. */
  isolation: isolate;
  /* FORA do .container e de ponta a ponta, como ele pediu. Sendo filha
     direta da <section>, 100% aqui é a largura da tela — e é %, não vw,
     porque vw conta a barra de rolagem e criaria rolagem horizontal.
     As bordas da arte não terminam em corte: o desvanecimento está
     ASSADO NO ALFA do próprio arquivo (ver convert-hero.js), não em
     mask-image, que é proibido no projeto, nem em degradê pintado por
     cima, que teria que acertar a cor de um fundo que não é chapado. */
  width: 100%;
  /* Sobe pra encostar no CTA, como na referência dele. A arte tem ~15%
     de céu vazio no topo, e sem esta puxada aquilo virava um buraco
     entre o botão e a cidade. A margem é em %, que resolve pela LARGURA
     do pai: como a proporção da imagem é fixa, o recuo acompanha o
     tamanho dela em qualquer tela. */
  margin: -8% auto 0;
  /* Ela passa por cima do CTA nessa puxada. Sem isto, a metade de baixo
     do botão pararia de receber clique — a figura é decorativa e não
     tem nada clicável dentro. */
  pointer-events: none;
}
/* A luz que assenta a peça na página. Medido no PNG: 46% dos pixels são
   OPACOS e quase pretos — ou seja, a arte é um bloco escuro, e sobre o
   roxo do fundo ela lia como recorte colado. Esta camada dá à borda o
   que ela não tem sozinha: uma transição. */
.cr-demo::before {
  content: '';
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 96%;
  height: 116%;
  border-radius: 50%;
  background:
    radial-gradient(46% 40% at 50% 48%, rgba(255,106,0,.42), rgba(255,106,0,.16) 58%, transparent 76%),
    radial-gradient(86% 74% at 50% 56%, rgba(155,95,255,.28), transparent 78%);
  filter: blur(40px);
  pointer-events: none;
}
/* NADA de filter nesta imagem. Já teve drop-shadow aqui pro bloom seguir
   a silhueta, e funcionava enquanto ela media 1040px. Ao crescer pra
   1354px a imagem PAROU DE APARECER — some inteira, sem erro no console,
   sobrando só o brilho de trás. Medido: com `filter: none` ela volta na
   hora. A área de filtro de um desfoque de 90px numa imagem desse tamanho
   é grande demais e o navegador desiste de pintar a camada. Todo o
   ambiente vem do ::before, que é um elemento pequeno e desenhado. */
.cr-demo img {
  display: block;
  width: 100%;
  height: auto;
}
@media (max-width: 720px) {
  .cr-demo::before { filter: blur(26px); }
}
@media (max-width: 900px) {
  /* O hero já é uma coluna só; aqui é só apertar o espaçamento e garantir
     que o traço do .section-tag não flutue no texto centralizado. */
  .cr-hero-inner { gap: 10px; text-align: center; }
  .cr-hero .section-lead { margin-left: auto; margin-right: auto; }
  .cr-hero-actions { justify-content: center; display: flex; }
  .cr-hero .section-tag { padding-left: 0; }
  .cr-hero .section-tag::before { display: none; }
}
@media (max-width: 720px) {
  .cr-hero { padding-top: 24px; padding-bottom: 0; }
  .cr-hero h1 { font-size: clamp(1.3rem, 5.6vw, 1.8rem); }
}

/* --- Bolinhas de destaque (/criativos/) ---------------------------- */
/* Quatro grupos, iguais no desktop e no celular. O que muda entre as
   duas telas é só o tamanho do círculo e do rótulo. */
.cr-destaques { align-items: flex-start; }
/* Largura fixa por item: sem ela cada bolinha ocupa a largura do proprio
   rotulo (de 67 a 102px com estes nomes), e o espacamento ENTRE os
   circulos sai desigual mesmo com o gap constante. Fixando a coluna, os
   circulos ficam equidistantes e o rotulo longo quebra em duas linhas
   dentro dela. */
.cr-destaque {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  width: 92px;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
/* O anel em degradê é o que faz a bolinha ler como "destaque de perfil".
   padding + background no pai desenha o aro; o miolo escuro por cima
   deixa só a borda aparecendo. */
.cr-destaque-anel {
  display: block;
  padding: 2.5px;
  border-radius: 50%;
  background: linear-gradient(140deg, #9b5fff, #c4a2ff 40%, #FF6A00);
  transition: transform .25s ease, filter .25s ease;
}
.cr-destaque-miolo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 62px;
  height: 62px;
  border-radius: 50%;
  background: #16121d;
  color: var(--text);
}
/* A marca dentro do circulo, como capa de destaque de perfil real —
   ele pediu que ficasse igual ao Instagram, entao e imagem de marca e
   nao icone de linha. */
.cr-destaque-miolo img { width: 34px; height: 34px; object-fit: contain; }
/* O primeiro circulo faz o papel do 'perfil' na referencia: anel puxando
   pro laranja, rotulo aceso e o selo '+'. Ele e decorativo (aria-hidden)
   e herda o clique do proprio link — nao promete uma acao separada. */
.cr-destaque--perfil .cr-destaque-anel { background: linear-gradient(140deg, #FF6A00, #ffb36b 45%, #9b5fff); }
.cr-destaque--perfil .cr-destaque-nome { color: var(--text); font-weight: 700; }
.cr-destaque-anel { position: relative; }
.cr-destaque-mais {
  position: absolute;
  right: -2px;
  bottom: -2px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid var(--bg);
  background: #2f7bf6;
  color: #fff;
  font-size: .8rem;
  font-weight: 700;
  line-height: 1;
}
.cr-destaque-nome {
  text-align: center;
  line-height: 1.25;
  font-size: .72rem;
  font-weight: 600;
  color: var(--text-muted);
  transition: color .2s ease;
}
@media (hover: hover) and (pointer: fine) {
  .cr-destaque:hover .cr-destaque-anel { transform: scale(1.07); filter: brightness(1.15); }
  .cr-destaque:hover .cr-destaque-nome { color: var(--text); }
}

/* Fundo sem laranja na /criativos/. O .bg-fx padrão tem três brilhos
   laranja e um roxo; aqui os quatro são roxos, porque roxo é a cor desta
   página e o laranja competia com ela.
   Reescreve a lista INTEIRA de background-image de propósito: sobrescrever
   só alguns brilhos é impossível numa lista de camadas — ou vem toda, ou
   herda toda. Por isso o grão, os pontinhos, o background-size e o
   background-repeat aparecem repetidos aqui. */
.bg-fx--roxo {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"),
    radial-gradient(circle at 12% 18%, rgba(155,95,255,.17), transparent 46%),
    radial-gradient(circle at 88% 12%, rgba(124,63,214,.13), transparent 42%),
    radial-gradient(circle at 92% 78%, rgba(155,95,255,.13), transparent 48%),
    radial-gradient(circle at 20% 92%, rgba(196,162,255,.08), transparent 44%),
    radial-gradient(rgba(255,255,255,.20) 1.5px, transparent 2.6px),
    radial-gradient(var(--bg-dot) 1px, transparent 1.6px);
  background-size: 140px 140px, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 168px 184px, 34px 34px;
  background-repeat: repeat, no-repeat, no-repeat, no-repeat, no-repeat, repeat, repeat;
}

/* --- Fileira de destaques: as mesmas quatro em toda tela ------------ */
/* Eram 7 no desktop e 4 agrupadas no celular; ele pediu as 4 nos dois
   (07/09). Quatro grupos dizem o mesmo que sete rótulos e sobra largura
   pro círculo crescer no desktop. */
.cr-destaques--grupos {
  display: flex;
  justify-content: center;
  gap: 10px;
  padding: 22px 12px 0;
}
@media (min-width: 901px) {
  .cr-destaques--grupos { gap: 26px; padding: 26px 24px 0; }
  .cr-destaques--grupos .cr-destaque { width: 118px; }
  .cr-destaques--grupos .cr-destaque-miolo { width: 78px; height: 78px; }
  .cr-destaques--grupos .cr-destaque-miolo img { width: 42px; height: 42px; }
  .cr-destaques--grupos .cr-destaque-nome { font-size: .78rem; }
}
@media (max-width: 900px) {
  /* 4 x 80 + 3 x 10 = 350px numa faixa útil de 354px em tela de 390.
     Com os 96px de antes (que serviam a três) dariam 438px e quebrariam
     linha. */
  .cr-destaques--grupos .cr-destaque { width: 80px; }
  .cr-destaques--grupos .cr-destaque-miolo { width: 62px; height: 62px; }
  .cr-destaques--grupos .cr-destaque-miolo img { width: 34px; height: 34px; }
  .cr-destaques--grupos .cr-destaque-nome { font-size: .66rem; }
}

/* O espaçador da fileira fixa mora FORA de qualquer media query: ele é
   uma div, e div sem regra é display:block. Enquanto as regras dele
   ficavam só dentro do @media do celular, no desktop ele virava um bloco
   com a altura da fileira — invisível só porque a fileira era
   display:none ali e media 0px de altura. Com a fileira visível nas duas
   telas, isso viraria um vão fixo no desktop. */
.cr-destaques-espaco { display: none; }
.cr-destaques-espaco.is-ativo { display: block; }

/* --- Visualizador de stories --------------------------------------- */
/* Desktop: a peça abre DENTRO de uma moldura de celular, pra dar a
   sensação de estar mexendo num telefone dentro do site. No celular a
   moldura não faz sentido (a pessoa já está num), então vira uma janela
   quase cheia — é a diferença que ele pediu. */
.cr-visor {
  position: fixed;
  inset: 0;
  z-index: 2500;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(6,6,9,.88);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  visibility: hidden;
  opacity: 0;
  transition: opacity .25s ease, visibility .25s ease;
}
.cr-visor.is-open { visibility: visible; opacity: 1; }

.cr-visor-janela {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(380px, 94vw);
  height: min(760px, 88vh);
  overflow: hidden;
  border-radius: 30px;
  background: #0b0910;
  /* A moldura: corpo do aparelho desenhado em volta da tela. */
  border: 9px solid #23232b;
  box-shadow: 0 30px 70px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.08);
}
@media (max-width: 900px) {
  .cr-visor { padding: 10px; }
  .cr-visor-janela {
    width: 100%;
    height: 96vh;
    border-width: 0;
    border-radius: 16px;
  }
}

/* Barrinhas de progresso, como no Instagram: uma por peça, a atual
   preenchendo no tempo da exibição. */
.cr-visor-barras {
  display: flex;
  gap: 4px;
  padding: 12px 12px 0;
}
.cr-visor-barra {
  flex: 1;
  height: 2.5px;
  border-radius: 999px;
  background: rgba(255,255,255,.28);
  overflow: hidden;
}
.cr-visor-barra i { display: block; height: 100%; width: 0; background: #fff; }

.cr-visor-topo {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 12px;
}
.cr-visor-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  padding: 2px;
  background: linear-gradient(140deg, #9b5fff, #FF6A00);
}
.cr-visor-avatar img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: #16121d;
  object-fit: contain;
}
.cr-visor-nome { font-size: .82rem; font-weight: 700; }
.cr-visor-contador { font-size: .72rem; color: rgba(255,255,255,.6); }
.cr-visor-fechar {
  margin-left: auto;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 50%;
  background: rgba(255,255,255,.12);
  color: #fff;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* O palco. A altura tem que descer em cadeia até a <img>, senão o
   max-height dela resolve contra altura AUTO (ou seja, contra nada) e
   uma peça 9:16 vaza a janela inteira — foi exatamente o que aconteceu:
   medido, imagem de 1599px de altura dentro de uma janela de 760px.
   Por isso o palco é bloco com altura de flex resolvida, o <article>
   herda 100% dela e a imagem usa object-fit em vez de max-height. */
.cr-visor-palco {
  flex: 1;
  min-height: 0;
  padding: 8px 12px;
}
.cr-visor-palco .cr-story { display: block; height: 100%; }
.cr-visor-palco img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 12px;
}


/* A peça de "Redes sociais": a única do visor que não é arte, e sim o
   fim da linha — mostrou o trabalho, agora dá o caminho. Ela ocupa o
   palco inteiro como uma peça faria, pra não quebrar o ritmo dos
   stories. */
.cr-visor-palco .cr-story--social {
  display: flex;
  height: 100%;
  border-radius: 12px;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 20% 0%, rgba(155,95,255,.45), transparent 62%),
    radial-gradient(100% 70% at 90% 100%, rgba(255,106,0,.35), transparent 60%),
    #16121f;
}
/* Sem isto as imagens daqui herdariam o width/height 100% + object-fit
   das peças de arte e cada ícone ocuparia o palco inteiro. E os dois
   tamanhos abaixo precisam do mesmo peso de seletor (.cr-visor-palco na
   frente), senão o auto acima vence os dois. */
.cr-visor-palco .cr-story--social img { width: auto; height: auto; }
.cr-visor-palco .cr-social-marca { width: 130px; max-width: 60%; height: auto; }
.cr-visor-palco .cr-social-btn img { width: 20px; height: 20px; flex: none; }

.cr-social {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  padding: 26px 22px;
  text-align: center;
}
.cr-social-marca { margin-bottom: 6px; }
.cr-social-titulo {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1.15;
  color: #fff;
}
.cr-social-lead {
  margin: 0 0 10px;
  font-size: .84rem;
  line-height: 1.45;
  color: rgba(255,255,255,.76);
}
.cr-social-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  max-width: 260px;
  min-height: 46px;
  padding: 12px 18px;
  border-radius: 999px;
  font-size: .88rem;
  font-weight: 700;
  color: #fff;
  -webkit-tap-highlight-color: transparent;
}
.cr-social-btn img { width: 20px; height: 20px; object-fit: contain; }
/* Acima das metades invisíveis de avançar/voltar do visor. Elas são
   position:absolute e vêm depois do palco no HTML, então pintam por cima
   dele — e a da direita cobre 66% da largura exatamente na altura destes
   botões. Sem isto, medido: o toque no meio do WhatsApp caía na metade
   de "avançar", nenhuma aba abria e o visor pulava pra Anúncios. */
.cr-visor-palco .cr-social-btn { position: relative; z-index: 2; }
.cr-social-btn--zap { background: #25D366; color: #08331a; }
.cr-social-btn--insta {
  background: linear-gradient(100deg, #F58529, #DD2A7B 55%, #8134AF);
}
@media (hover: hover) and (pointer: fine) {
  .cr-social-btn:hover { transform: translateY(-2px); }
}
.cr-social-btn { transition: transform .18s ease; }

.cr-visor-rodape { padding: 10px 12px 14px; }
.cr-visor-msg {
  display: block;
  padding: 11px 16px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.06);
  text-align: center;
  font-size: .8rem;
  font-weight: 600;
  -webkit-tap-highlight-color: transparent;
}

/* Metades invisíveis para avançar/voltar tocando, como no Instagram.
   Ficam abaixo do topo e do rodapé no z-index pra não roubar o clique
   do botão de fechar nem do CTA. */
.cr-visor-lado {
  position: absolute;
  top: 60px;
  bottom: 64px;
  width: 34%;
  border: none;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.cr-visor-lado--esq { left: 0; }
.cr-visor-lado--dir { right: 0; width: 66%; }

/* Variante de uma coluna da tabela, para a /criativos/: ali é um serviço
   só, então não há o que comparar — a tabela vira "o que entra em toda
   peça". A coluna do ✓ encolhe e o rótulo ganha o espaço. */
.lp-compare--simples .lp-compare-table td { width: 44px; }
.lp-compare--simples .lp-compare-price td {
  width: auto;
  text-align: right;
  white-space: nowrap;
}

/* Fileira fixa no topo ao rolar — só no celular, como ele pediu.
   Nada de position:sticky aqui: o html tem overflow-x:hidden e isso
   quebra sticky (medido, a fileira subia junto com a página, topo em
   -822). Quem troca pra position:fixed é o main.js, e um espaçador
   assume a altura dela enquanto está fixa, pra página não pular. */
@media (max-width: 900px) {
  /* Cartão flutuante, não faixa colada: recuo nas três bordas e cantos
     arredondados, pra ele não encostar em lugar nenhum da tela.
     Sem faixa reservada pro cabeçalho: medido, ele NÃO fica no topo — o
     mesmo overflow-x:hidden que quebrou o sticky da fileira quebra o
     dele, e o menu sai da tela ao rolar (topo em -677). A fileira sobe
     junto e assume o topo quando ele some. */
  .cr-destaques--grupos.is-fixa {
    position: fixed;
    top: 10px;
    left: 10px;
    right: 10px;
    z-index: 400;
    padding-top: 12px;
    padding-bottom: 10px;
    border-radius: 20px;
    border: 1px solid rgba(255,255,255,.10);
    background: rgba(19,19,22,.88);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 14px 30px rgba(0,0,0,.42);
    /* A transição mora AQUI, no estado fixo, e não na fileira solta.
       Estando na fileira, ela valia nos dois sentidos: ao voltar pro
       topo, o position já era static (instantâneo) enquanto o fundo e a
       sombra ainda levavam 250ms pra sumir — e no meio disso aparecia
       uma faixa escura de ponta a ponta, sem os cantos arredondados,
       que é o defeito que ele viu. Declarada só no estado fixo, ela
       anima ao grudar e desaparece na hora ao soltar. */
    transition: background .25s ease, box-shadow .25s ease, padding .25s ease;
  }
  /* Encolhe um pouco quando fixa, pra devolver tela ao conteúdo. */
  .cr-destaques--grupos.is-fixa .cr-destaque-miolo { width: 52px; height: 52px; }
  .cr-destaques--grupos.is-fixa .cr-destaque-miolo img { width: 28px; height: 28px; }
  .cr-destaques--grupos.is-fixa .cr-destaque-nome { font-size: .6rem; }
}

/* No desktop ela não gruda no topo: vira uma doca flutuante no rodapé,
   como ele pediu, e só aparece depois que a fileira sai inteira de vista
   (o gatilho com "+ altura" está no main.js). Pílula centralizada, no
   formato da referência que ele mandou. */
@media (min-width: 901px) {
  .cr-destaques--grupos.is-fixa {
    position: fixed;
    top: auto;
    bottom: 22px;
    left: 50%;
    z-index: 400;
    width: auto;
    gap: 18px;
    padding: 12px 24px 10px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,.12);
    background: rgba(19,19,22,.9);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    box-shadow: 0 18px 40px rgba(0,0,0,.5);
    /* Animação em vez de transição: o estado fixo nasce já com
       translateX(-50%), e uma transição partiria do translate anterior
       (nenhum), fazendo a doca entrar deslizando de lado. */
    transform: translateX(-50%);
    animation: doca-entra .22s ease-out;
  }
  /* Menor aqui do que na página: a doca é atalho, não a fileira. */
  .cr-destaques--grupos.is-fixa .cr-destaque { width: 84px; gap: 6px; }
  .cr-destaques--grupos.is-fixa .cr-destaque-miolo { width: 46px; height: 46px; }
  .cr-destaques--grupos.is-fixa .cr-destaque-miolo img { width: 25px; height: 25px; }
  .cr-destaques--grupos.is-fixa .cr-destaque-nome { font-size: .62rem; }
  .cr-destaques--grupos.is-fixa .cr-destaque-mais { width: 14px; height: 14px; font-size: .62rem; }
}
@keyframes doca-entra {
  from { opacity: 0; transform: translate(-50%, 16px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .cr-destaques--grupos.is-fixa { animation: none; }
}

/* O metalizado dentro de texto corrido precisa de uma rampa mais clara.
   A original vai quase ao preto nas pontas (#3d1f73), o que funciona num
   título grande e bold mas, numa palavra pequena no meio de um parágrafo
   claro, deixa a palavra MENOS legível que o texto em volta — o efeito
   passa a esconder em vez de destacar. Aqui os extremos sobem para um
   roxo médio e o miolo fica quase branco. */
.section-lead .text-shine-purple,
.cr-hero .section-lead .text-shine-purple {
  background: linear-gradient(95deg, #8b63d6 0%, #b48cff 20%, #ddccff 42%, #ffffff 52%, #ddccff 62%, #b48cff 82%, #8b63d6 100%);
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  text-shadow: 0 0 14px rgba(155,95,255,.3);
}
