/* ==========================================================================
   L&D ENGENHARIA
   Wine + cream, Syne + Inter. Hairline rules, ruled lists and panel cells
   carry the structure; motion is masked type reveals plus pointer tilt.
   ========================================================================== */

:root {
  /* brand */
  --vinho:        #581328;
  --vinho-dark:   #3d0c1c;
  --vinho-mid:    #701634;
  --vinho-bright: #8B2042;

  /* surfaces */
  --creme:  #f0eae5;
  --paper:  #f7f3f0;
  --white:  #ffffff;

  /* ink */
  --ink:    #1a0a0e;
  --muted:  #7a5c64;

  /* the hairline that carries the world */
  --line:    rgba(88, 19, 40, 0.13);
  --line-2:  rgba(88, 19, 40, 0.26);
  --line-on-dark:   rgba(240, 234, 229, 0.18);
  --line-on-dark-2: rgba(240, 234, 229, 0.34);

  --font-display: 'Syne', system-ui, sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, sans-serif;

  --ease-out:  cubic-bezier(0.16, 1, 0.3, 1);
  --ease-soft: cubic-bezier(0.33, 1, 0.68, 1);

  --nav-h: 76px;
  /* the gutter is fluid, so nothing between the breakpoints has to restate it */
  --gutter: clamp(20px, 3.4vw, 40px);
  --section-y: clamp(72px, 11vw, 152px);

  /* Two measures. Sections sit on --content-max through .container. The
     blocks that run edge to edge — nav, hero, diferencial — sit on the
     wider --bleed-max through the --edge pair: 1840px is exactly the
     gutter-to-gutter width of a 1920 screen, so nothing below 1920 moves
     and everything above it stops spreading. The same pair keeps content
     clear of the cutout on a notched phone held sideways. */
  --content-max: 1240px;
  --bleed-max: 1840px;
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --pad-l: max(var(--gutter), var(--safe-l));
  --pad-r: max(var(--gutter), var(--safe-r));
  --edge-l: max(var(--pad-l), calc((100% - var(--bleed-max)) / 2));
  --edge-r: max(var(--pad-r), calc((100% - var(--bleed-max)) / 2));

  /* the hamburger's centre — the origin the mobile menu opens from */
  --menu-x: calc(100% - var(--pad-r) - 22px);
  --menu-y: calc(var(--nav-h) / 2);

  --shadow-sm: 0 2px 6px rgba(61, 12, 28, 0.05), 0 8px 24px rgba(61, 12, 28, 0.06);
  --shadow-md: 0 6px 16px rgba(61, 12, 28, 0.08), 0 22px 48px rgba(61, 12, 28, 0.10);
  --shadow-lg: 0 10px 28px rgba(61, 12, 28, 0.12), 0 36px 80px rgba(61, 12, 28, 0.16);
}

/* A registered property: only a typed custom property can be interpolated,
   which is what lets the conic ring on .pilar actually rotate. */
@property --ring-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

/* ---------------------------------------------------------------- reset */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  /* 100%, not 16px: a reader who has raised their browser's base size keeps
     it, and every rem-based clamp scales with them */
  font-size: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 16px);
  -webkit-text-size-adjust: 100%;
  /* the gutter is held even while the mobile menu pins the body, so opening
     it cannot widen the page by a scrollbar's width */
  scrollbar-gutter: stable;
}

body {
  font-family: var(--font-body);
  background: var(--creme);
  color: var(--ink);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The menu's scroll lock. `overflow: hidden` alone does not hold on iOS
   Safari, so the body is pinned and its offset is restored on close. */
body.is-locked {
  position: fixed;
  left: 0; right: 0;
  width: 100%;
  overflow: hidden;
}

img { max-width: 100%; display: block; }
ul, ol { list-style: none; }
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
h1, h2, h3, h4, h5, p, li, a, span { overflow-wrap: break-word; }
h1, h2, h3, h4, h5 { text-wrap: balance; }
p { text-wrap: pretty; }
svg { display: block; }

/* ------------------------------------------------- browser surfaces
   The parts we did not draw still carry the design.                    */
::selection { background: var(--vinho); color: var(--creme); }
:where(input, textarea) { caret-color: var(--vinho); }

html { scrollbar-color: var(--line-2) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--creme); }
::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border: 3px solid var(--creme);
  border-radius: 100px;
}
::-webkit-scrollbar-thumb:hover { background: var(--vinho); }

:focus-visible {
  outline: 2px solid var(--vinho);
  outline-offset: 3px;
  border-radius: 3px;
}
.diferencial :focus-visible,
.footer :focus-visible,
.mobile-menu :focus-visible { outline-color: var(--creme); }

.skip-link {
  position: fixed;
  top: max(12px, env(safe-area-inset-top, 0px));
  left: max(12px, var(--safe-l));
  z-index: 200;
  padding: 12px 20px;
  background: var(--vinho);
  color: var(--creme);
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 700;
  border-radius: 100px;
  transform: translateY(-150%);
  transition: transform 0.25s var(--ease-out);
}
.skip-link:focus-visible { transform: translateY(0); }

/* ---------------------------------------------------------- primitives */
.container {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--pad-l) var(--pad-r);
}

.section-title {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 4.4vw, 3.25rem);
  font-weight: 800;
  line-height: 1.06;
  letter-spacing: -0.03em;
  color: var(--vinho-dark);
  max-width: 18ch;
}
.section-sub {
  margin-top: 20px;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--muted);
  max-width: 56ch;
}
.section-head { margin-bottom: clamp(48px, 6vw, 76px); }

/* -------------------------------------------------------------- buttons */
.btn {
  --btn-fg: var(--creme);
  --btn-bg: var(--vinho);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  /* Both caps top out around 790px, so every desktop width keeps the
     original 15px/30px box; only phones scale down with the title. */
  padding: clamp(12px, 1.9vw, 15px) clamp(20px, 3.8vw, 30px);
  border: 1.5px solid var(--btn-bg);
  border-radius: 100px;
  background: transparent;
  color: var(--btn-fg);
  font-family: var(--font-display);
  font-size: clamp(0.8rem, 1.82vw, 0.9rem);
  font-weight: 700;
  letter-spacing: 0.01em;
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.3s var(--ease-out),
              border-color 0.3s var(--ease-out),
              box-shadow 0.4s var(--ease-out);
}
/* the fill wipes up from the floor — one gesture, reused everywhere */
.btn::before {
  content: '';
  position: absolute;
  inset: -1px;
  z-index: -1;
  background: var(--btn-bg);
  transform: scaleY(1);
  transform-origin: bottom;
  transition: transform 0.42s var(--ease-out);
}
.btn:hover::before,
.btn:focus-visible::before { transform: scaleY(0); transform-origin: top; }

.btn--primary { --btn-bg: var(--vinho); --btn-fg: var(--creme); }
.btn--primary:hover,
.btn--primary:focus-visible {
  color: var(--vinho);
  box-shadow: 0 14px 34px rgba(88, 19, 40, 0.22);
}

.btn--ghost { --btn-bg: transparent; --btn-fg: var(--vinho); border-color: var(--line-2); }
.btn--ghost::before { background: var(--vinho); transform: scaleY(0); transform-origin: bottom; }
.btn--ghost:hover::before,
.btn--ghost:focus-visible::before { transform: scaleY(1); }
.btn--ghost:hover,
.btn--ghost:focus-visible { color: var(--creme); border-color: var(--vinho); }

.btn--full { width: 100%; }
.btn__label { position: relative; }

.arrow {
  width: clamp(15px, 2.2vw, 17px);
  height: clamp(15px, 2.2vw, 17px);
  flex-shrink: 0;
  transition: transform 0.35s var(--ease-out);
}
.btn:hover .arrow,
.btn:focus-visible .arrow { transform: translateX(5px); }

/* submit states */
.btn__spinner {
  position: absolute;
  width: 19px; height: 19px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  opacity: 0;
}
.btn.is-sending { pointer-events: none; }
.btn.is-sending .btn__label,
.btn.is-sending .arrow { opacity: 0; }
.btn.is-sending .btn__spinner { opacity: 1; animation: spin 0.7s linear infinite; }
.btn:disabled { cursor: not-allowed; }
.btn.is-sent::before { transform: scaleY(1); transform-origin: bottom; }

@keyframes spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------- reveal system
   Gated on .js so a failed script never hides the page.                */
.js [data-reveal] {
  opacity: 0;
  /* `translate` is its own property, so it composes with `transform` instead
     of replacing it — a card can carry the reveal offset AND its 3D tilt. */
  translate: 0 26px;
}
/* Driven by an animation rather than a transition: `transition` is a single
   property, so declaring it here would out-specify and wipe out every
   element's own hover transition (border, shadow, tilt return). */
.js [data-reveal].is-in { animation: revealIn 0.75s var(--ease-out) both; }
@keyframes revealIn {
  from { opacity: 0; translate: 0 26px; }
  to   { opacity: 1; translate: none; }
}

/* masked line rise — used for the hero title and every section title.
   The padding/negative-margin pair gives descenders room to live inside an
   overflow-hidden shell without changing the line box. */
.ln, .w {
  display: block;
  overflow: hidden;
  padding-bottom: 0.16em;
  margin-bottom: -0.16em;
}
.w { display: inline-block; vertical-align: top; }
.ln__i, .w__i { display: inline-block; }
.js .ln__i, .js .w__i { transform: translate3d(0, 120%, 0); }
.js .is-in .ln__i,
.js .is-in .w__i,
.js .hero.is-ready .ln__i {
  transform: translate3d(0, 0, 0);
  transition: transform 0.9s var(--ease-out);
  transition-delay: calc(var(--wi, 0) * 42ms);
}
/* Scrubbed text is driven frame by frame from the scroll position, so it must
   not ease or stagger on its own — the scroll is the timeline. */
.js [data-scrub] .w__i {
  transition: none !important;
  transition-delay: 0s !important;
}
/* A transform written from script is not a compositor animation, so without
   a layer of its own each word rewrite repainted display-size text — and the
   masked blueprint sitting under it — on the main thread, sixty times a
   second. `.is-scrubbing` is put on by the observer only while the quote is
   near its band and taken off again on the way out, so the layers are held
   for the seconds they earn and released the rest of the time. */
.js [data-scrub].is-scrubbing .w__i { will-change: transform; }
.js .hero.is-ready .ln__i { transition-delay: calc(var(--wi, 0) * 90ms); }

/* headings stay blank until the script has split them, so the words never
   flash in place before dropping */
.js [data-split] { opacity: 0; }
.js [data-split].is-split { opacity: 1; }

/* ============================================================== NAV ==== */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* --edge keeps the bar's contents on the same measure as every section,
     so on an ultrawide screen the logo and the links do not end up a foot
     apart with nothing between them */
  padding-inline: var(--edge-l) var(--edge-r);
  background: rgba(240, 234, 229, 0.72);
  backdrop-filter: blur(12px) saturate(1.35);
  -webkit-backdrop-filter: blur(12px) saturate(1.35);
  border-bottom: 1px solid transparent;
  /* The bar is fixed and slides on transform; the hint keeps it on one
     stable layer instead of being promoted and dropped around each move. */
  will-change: transform;
  transition: transform 0.5s var(--ease-out),
              background 0.4s ease,
              border-color 0.4s ease;
}
/* Re-blurring the full width of the viewport behind a fixed bar is the most
   expensive thing on this page and the compositor redoes it on every
   scrolled frame — it was costing frames in every section, not just here.
   Stuck, the bar sits at 94% creme, where a blur behind it cannot be seen;
   so the filter is dropped for the whole time the reader is scrolling and
   kept only at the top of the page, where the bar really is glass. */
.nav.is-stuck {
  background: rgba(240, 234, 229, 0.94);
  border-bottom-color: var(--line);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.nav.is-hidden { transform: translate3d(0, -100%, 0); }

/* A sibling of the nav, never a child — so the nav hiding cannot take it
   along. It rides just under the nav while the nav is out, and slides up to
   the top edge of the screen when the nav retracts. The wrapper owns the
   vertical follow; the fill owns the horizontal progress, so the progress
   never inherits the follow's easing. */
.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  z-index: 120;
  width: 100%;
  height: 3px;
  pointer-events: none;
  transform: translate3d(0, var(--nav-h), 0);
  transition: transform 0.5s var(--ease-out);
}
.scroll-progress.is-top { transform: translate3d(0, 0, 0); }
.scroll-progress__fill {
  display: block;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, var(--vinho), var(--vinho-bright));
  transform: scaleX(var(--p, 0));
  transform-origin: left center;
}

.nav__logo { display: flex; align-items: center; gap: 10px; min-width: 0; }
.nav__logo-img {
  width: 3.1rem; height: 3.1rem;
  object-fit: contain;
  flex-shrink: 0;
  transition: transform 0.5s var(--ease-out);
}
.nav__logo:hover .nav__logo-img { transform: rotate(-8deg) scale(1.06); }
.nav__logo-text {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--vinho);
  white-space: nowrap;
}
.nav__logo-text .amp { color: var(--vinho-bright); }

.nav__links { display: flex; align-items: center; gap: 34px; }
.nav__link {
  display: inline-block;
  overflow: hidden;
  font-family: var(--font-display);
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--vinho);
}
/* the label rolls up and its twin rolls in — the same masked-rise gesture
   the hero title uses, so the nav speaks the page's own motion language */
.nav__link-i {
  display: block;
  position: relative;
  line-height: 1.7;
  transition: transform 0.45s var(--ease-out);
}
.nav__link-i::after {
  content: attr(data-label);
  position: absolute;
  left: 0; top: 100%;
  width: 100%;
  color: var(--vinho-dark);
}
.nav__link:hover .nav__link-i,
.nav__link:focus-visible .nav__link-i { transform: translateY(-100%); }
.nav__link.is-active { color: var(--vinho-dark); font-weight: 700; }

.nav__link--cta {
  padding: 11px 24px;
  border-radius: 100px;
  background: var(--vinho);
  color: var(--creme);
  transition: background 0.3s, box-shadow 0.3s;
}
.nav__link--cta:hover {
  background: var(--vinho-dark);
  box-shadow: 0 10px 26px rgba(88, 19, 40, 0.26);
}

/* hamburger */
.nav__hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 44px; height: 44px;
  background: none;
  border: none;
  cursor: pointer;
  z-index: 101;
}
.nav__hamburger span {
  display: block;
  width: 24px; height: 1.5px;
  background: var(--vinho);
  transition: transform 0.4s var(--ease-out), opacity 0.2s ease, background 0.3s;
}
.nav__hamburger.is-open span { background: var(--creme); }
.nav__hamburger.is-open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav__hamburger.is-open span:nth-child(2) { opacity: 0; transform: scaleX(0.2); }
.nav__hamburger.is-open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* mobile menu — a scroller, because five rows of display type do not fit a
   phone held sideways. The list is centred with `margin: auto` rather than
   by the flex container: auto margins collapse to zero once the content is
   taller than the box, so the first item can never end up above the scroll
   origin the way flex centring puts it. */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 99;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: calc(var(--nav-h) + 8px) var(--pad-r)
           calc(24px + env(safe-area-inset-bottom, 0px)) var(--pad-l);
  background: var(--vinho);
  opacity: 0;
  visibility: hidden;
  clip-path: circle(0% at var(--menu-x) var(--menu-y));
  transition: opacity 0.3s ease,
              visibility 0.45s,
              clip-path 0.65s var(--ease-out);
}
.mobile-menu.is-open {
  opacity: 1;
  visibility: visible;
  clip-path: circle(150% at var(--menu-x) var(--menu-y));
}
.mobile-menu ul { width: min(420px, 100%); margin: auto; }

/* While the menu is open its wine panel sits directly behind the bar, and
   72% creme over wine reads as pink. So the bar drops its translucency for
   the duration and goes to solid creme. The burger has to come back with
   it: its strokes turn creme for the wine panel, which would be invisible
   against a creme bar. */
body.menu-open .nav {
  background: var(--creme);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
body.menu-open .nav__hamburger.is-open span { background: var(--vinho); }
.mobile-menu li { border-bottom: 1px solid var(--line-on-dark); }
.mobile-link {
  display: flex;
  align-items: baseline;
  gap: 18px;
  padding: 22px 4px;
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 7vw, 2.2rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--creme);
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity 0.4s ease, transform 0.55s var(--ease-out);
}
.mobile-menu.is-open .mobile-link { opacity: 1; transform: none; }
.mobile-menu.is-open li:nth-child(1) .mobile-link { transition-delay: 0.14s; }
.mobile-menu.is-open li:nth-child(2) .mobile-link { transition-delay: 0.20s; }
.mobile-menu.is-open li:nth-child(3) .mobile-link { transition-delay: 0.26s; }
.mobile-menu.is-open li:nth-child(4) .mobile-link { transition-delay: 0.32s; }
.mobile-menu.is-open li:nth-child(5) .mobile-link { transition-delay: 0.38s; }

/* ============================================================= HERO ==== */
.hero {
  position: relative;
  /* svh is the small viewport: the height that survives the mobile address
     bar expanding. The vh line above it is the fallback for browsers that
     do not know the unit. */
  min-height: 100vh;
  min-height: 100svh;
  padding-block: calc(var(--nav-h) + 24px) 0;
  padding-inline: var(--edge-l) var(--edge-r);
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  grid-template-rows: 1fr auto;
  align-items: center;
  gap: 0 56px;
  overflow: hidden;
  background: var(--creme);
}

/* blueprint grid + a warm wine glow behind the logo */
.hero__blueprint {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(to right,  var(--line) 0 1px, transparent 1px 88px),
    repeating-linear-gradient(to bottom, var(--line) 0 1px, transparent 1px 88px);
  -webkit-mask-image: radial-gradient(115% 90% at 68% 42%, #000 12%, transparent 78%);
          mask-image: radial-gradient(115% 90% at 68% 42%, #000 12%, transparent 78%);
  opacity: 0;
}
.js .hero.is-ready .hero__blueprint { opacity: 1; transition: opacity 1.4s 0.15s ease; }
.no-js .hero__blueprint { opacity: 1; }

.hero__bg-text {
  position: absolute;
  top: 50%; left: 50%;
  font-family: var(--font-display);
  font-size: clamp(90px, 17vw, 232px);
  font-weight: 800;
  letter-spacing: -0.04em;
  color: rgba(88, 19, 40, 0.07);
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
  /* --drift is the scroll distance, written by the motion layer; where the
     word sits and which way it faces are decided here, so the narrow layout
     can stand the same element on its end without the script knowing. */
  transform: translate3d(-50%, calc(-50% + var(--drift, 0px)), 0);
}
/* The word is only rewritten while the hero is on screen, so the layer is
   only worth holding for that long. The observer in js/main.js carries the
   class, the same way `.is-scrubbing` carries the quote's — on a phone this
   is display-size type standing the full height of the screen, and keeping
   its texture alive for the other ten thousand pixels of the page is memory
   Safari would rather spend on what is actually being looked at. */
.hero__bg-text.is-drifting { will-change: transform; }
/* it drifts with the scroll (JS) and fades up with the rest of the hero */
.js .hero__bg-text { opacity: 0; }
.js .hero.is-ready .hero__bg-text {
  opacity: 1;
  transition: opacity 1.6s 0.35s var(--ease-out);
}
.no-js .hero__bg-text { opacity: 1; }

.hero__content { grid-area: 1 / 1; position: relative; z-index: 2; padding-block: 40px; min-width: 0; }

.hero__title {
  font-family: var(--font-display);
  /* The slope is set by the longest line ("com propósito", ~11.1x its own
     font size in Syne 800) against the width of the 1.05fr text column —
     not by taste. At 5.6vw the line outgrew its column on every laptop
     between 1280 and 1800 and wrapped into the masked shell. */
  font-size: clamp(1.75rem, 4.05vw, 5rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.035em;
  color: var(--vinho-dark);
  margin-bottom: 30px;
}
.hero__accent { font-style: normal; color: var(--vinho); position: relative; }
.hero__accent::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0.08em;
  height: 5px;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--vinho), transparent);
  opacity: 0.4;
}

.hero__subtitle {
  max-width: 50ch;
  font-size: 1.08rem;
  line-height: 1.72;
  color: var(--muted);
  margin-bottom: 36px;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 40px; }

.hero__credential {
  display: flex;
  align-items: center;
  gap: 16px;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.hero__credential-rule {
  width: 48px; height: 1px;
  flex-shrink: 0;
  background: var(--line-2);
}

/* staged entrance for everything under the title */
.js .hero__subtitle,
.js .hero__actions,
.js .hero__credential {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
}
.js .hero.is-ready .hero__subtitle,
.js .hero.is-ready .hero__actions,
.js .hero.is-ready .hero__credential {
  opacity: 1;
  transform: none;
  transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out);
}
.js .hero.is-ready .hero__subtitle   { transition-delay: 0.62s; }
.js .hero.is-ready .hero__actions    { transition-delay: 0.74s; }
.js .hero.is-ready .hero__credential { transition-delay: 0.86s; }

/* ---- the logo: 3D tilt on a slow float ---- */
.hero__visual {
  grid-area: 1 / 2;
  display: grid;
  place-items: center;
  min-width: 0;
}
/* .hero__logo-tilt is the hit area and stays put; .hero__logo-3d tilts. */
.hero__logo-tilt { position: relative; z-index: 2; }
.hero__logo-3d {
  transform: perspective(500px)
             rotateY(calc(var(--rx, 0) * 1deg))
             rotateX(calc(var(--ry, 0) * -1deg))
             scale(var(--s, 1));
  transition: transform 0.9s var(--ease-out);
}
.hero__logo-3d.is-tracking { --s: 1.07; transition: transform 0.12s ease-out; }
.hero__logo-float { animation: logoFloat 4s ease-in-out infinite; }
.hero__logo-wrap {
  display: grid;
  place-items: center;
  width: 268px; height: 268px;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, var(--vinho-mid), var(--vinho) 52%, var(--vinho-dark));
  box-shadow: 0 30px 70px -18px rgba(61, 12, 28, 0.45),
              0 4px 14px -4px rgba(61, 12, 28, 0.2),
              inset 0 3px 18px rgba(255, 255, 255, 0.14);
  opacity: 0;
  transform: scale(0.9);
}
.js .hero.is-ready .hero__logo-wrap {
  opacity: 1;
  transform: scale(1);
  transition: opacity 0.9s 0.45s var(--ease-out), transform 1.1s 0.45s var(--ease-out);
}
.no-js .hero__logo-wrap { opacity: 1; transform: none; }
/* `height: auto` is doing real work, not restating a default. The tag now
   carries width/height attributes so the box is reserved before the file
   arrives, and an HTML height attribute lands as a presentational
   `height: 500px` that this rule's `width` cannot override on its own —
   the frame would be 176 wide and 500 tall. `auto` hands the height back
   to the aspect ratio, which is where it already was. */
.hero__logo-img { width: 176px; height: auto; object-fit: contain; }

@keyframes logoFloat {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -14px, 0); }
}

/* ---- stats: a specification strip on the rule ---- */
.hero__stats {
  grid-area: 2 / 1 / 3 / -1;
  display: grid;
  /* Equal thirds sized the BOXES evenly but left every reading ragged at the
     start of its own third, so the last one's ink stopped near the middle of
     the rule. Content-sized tracks pushed apart hang the first off the left
     edge and the last off the right, and the strip spans its own line. */
  grid-template-columns: repeat(3, auto);
  justify-content: space-between;
  border-top: 1px solid var(--line-2);
  margin-top: 24px;
}
.stat:last-child { padding-right: 0; }
.stat {
  padding: 26px 24px 44px 0;
  position: relative;
  opacity: 0;
  transform: translate3d(0, 14px, 0);
}
.stat + .stat { padding-left: 24px; }
.stat + .stat::before {
  content: '';
  position: absolute;
  left: 0; top: 26px;
  width: 1px; height: 28px;
  background: var(--line-2);
}
.js .hero.is-ready .stat {
  opacity: 1; transform: none;
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}
.js .hero.is-ready .stat:nth-child(1) { transition-delay: 1.00s; }
.js .hero.is-ready .stat:nth-child(2) { transition-delay: 1.10s; }
.js .hero.is-ready .stat:nth-child(3) { transition-delay: 1.20s; }
.no-js .stat { opacity: 1; transform: none; }

.stat__label {
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 10px;
}
.stat__value {
  font-family: var(--font-display);
  /* 2.85vw holds the number at 0.70 of the title across the desktop range
     and hits the same 3.4rem ceiling at 1909px the fixed value used to sit
     at, so wide screens are unchanged; the 1.35rem floor keeps it under the
     title down to 320px, where the title itself is only 24px. */
  font-size: clamp(1.35rem, 2.85vw, 3.4rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--vinho);
  font-variant-numeric: tabular-nums;
}
.stat__value i { font-style: normal; font-size: 0.5em; vertical-align: super; color: var(--vinho-bright); }

/* ========================================================== MARQUEE ==== */
.marquee {
  background: var(--vinho);
  overflow: hidden;
  padding-block: 17px;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
/* 23s, not 46s, and the speed on screen is unchanged: each track now holds
   the seven-word cycle once instead of twice, so the -50% the animation
   travels is half the distance it used to be. The fita that gets composited
   is half as wide with it — it was around 4000px, and a layer that wide has
   to be split into tiles and re-rastered as it moves on a phone. */
.marquee__inner { display: flex; width: max-content; animation: marquee 23s linear infinite; }
.marquee:hover .marquee__inner { animation-play-state: paused; }
.marquee__track { display: flex; align-items: center; gap: 30px; padding-right: 30px; flex-shrink: 0; }
.marquee__track span {
  font-family: var(--font-display);
  font-size: 0.84rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--creme);
  white-space: nowrap;
}
.marquee__track .dot {
  width: 4px; height: 4px;
  border-radius: 50%;
  background: rgba(240, 234, 229, 0.4);
  flex-shrink: 0;
}
@keyframes marquee { to { transform: translate3d(-50%, 0, 0); } }

/* Off the screen, off the clock. Set by the observer in js/main.js on the
   two continuous loops — this one and the logo's float. A paused animation
   is not advanced and not composited; both resume on the phase they were
   left on, which is the phase the reader would have come back to. */
.marquee__inner.is-paused,
.hero__logo-float.is-paused { animation-play-state: paused; }

/* ============================================================ SOBRE ==== */
.sobre { padding-block: var(--section-y); background: var(--white); }
.sobre__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 72px;
  align-items: start;
}
.sobre__text {
  margin-top: 26px;
  font-size: 1.02rem;
  line-height: 1.8;
  color: var(--muted);
  max-width: 60ch;
}

/* pilares: the mark carries wine at rest so each row reads as an object, and
   the panel steps forward on hover rather than growing a rule. */
.pilares { display: grid; gap: 14px; }

.pilar {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "mark title" "mark text";
  gap: 7px 20px;
  padding: 26px 28px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--creme);
  transition: background 0.45s var(--ease-out),
              border-color 0.45s var(--ease-out),
              box-shadow 0.5s var(--ease-out);
}
/* A conic gradient is traced around the card's edge. `--ring-angle` is a
   REGISTERED custom property (@property below): without registration the
   browser treats it as a string and the angle cannot animate at all. The
   double mask paints the gradient only in the 1.5px border band, which is how
   you get a gradient border without border-image. */
.pilar::before {
  content: '';
  position: absolute;
  inset: -1px;
  z-index: 0;
  border-radius: inherit;
  padding: 2.2px;
  background: conic-gradient(from var(--ring-angle, 0deg),
              transparent 0deg,
              rgba(139, 32, 66, 0.35) 25deg,
              var(--vinho-bright) 70deg,
              var(--vinho) 120deg,
              rgba(88, 19, 40, 0.3) 175deg,
              transparent 215deg,
              transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.4s var(--ease-out);
  pointer-events: none;
}
.pilar:hover::before,
.pilar:focus-within::before {
  opacity: 1;
  animation: ringTrace 2.6s linear infinite;
}
@keyframes ringTrace { to { --ring-angle: 360deg; } }

/* the surface itself only deepens — the ring carries the gesture */
.pilar:hover {
  background: var(--white);
  box-shadow: 0 20px 44px -20px rgba(61, 12, 28, 0.5);
}
.pilar__mark, .pilar__title, .pilar__text { position: relative; z-index: 1; }

.pilar__mark {
  grid-area: mark;
  align-self: start;
  display: grid;
  place-items: center;
  width: 54px; height: 54px;
  margin-top: 2px;
  border-radius: 17px;
  background: linear-gradient(148deg, var(--vinho-mid), var(--vinho) 52%, var(--vinho-dark));
  color: var(--creme);
  box-shadow: 0 10px 22px -10px rgba(88, 19, 40, 0.6);
  transition: transform 0.5s var(--ease-out), box-shadow 0.5s var(--ease-out);
}
.pilar__mark svg { width: 26px; height: 26px; }
.pilar:hover .pilar__mark {
  transform: scale(1.06);
  box-shadow: 0 16px 30px -10px rgba(88, 19, 40, 0.75),
              0 0 0 6px rgba(88, 19, 40, 0.08);
}
.pilar:hover .pilar__mark svg > * { animation: markDraw 0.7s var(--ease-out) both; }
.pilar:hover .pilar__mark svg > *:nth-child(2) { animation-delay: 0.08s; }
.pilar:hover .pilar__mark svg > *:nth-child(3) { animation-delay: 0.16s; }
.pilar:hover .pilar__mark svg > *:nth-child(4) { animation-delay: 0.24s; }
@keyframes markDraw {
  from { stroke-dasharray: 90; stroke-dashoffset: 90; }
  to   { stroke-dasharray: 90; stroke-dashoffset: 0; }
}

.pilar__title {
  grid-area: title;
  font-family: var(--font-display);
  font-size: 1.26rem;
  font-weight: 700;
  letter-spacing: -0.018em;
  color: var(--vinho-dark);
  transition: color 0.45s var(--ease-out);
}
.pilar__text {
  grid-area: text;
  max-width: 52ch;
  font-size: 0.94rem;
  line-height: 1.74;
  color: var(--muted);
  transition: color 0.45s var(--ease-out);
}

/* ========================================================= SERVIÇOS ==== */
.servicos { padding-block: var(--section-y); background: var(--creme); }

/* Cells share one hairline instead of floating apart, so the block reads as a
   single instrument panel. */
.servicos__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--line-2);
  border: 1px solid var(--line-2);
  border-radius: 18px;
  overflow: hidden;
}

.servico {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 34px 32px 32px;
  background: var(--white);
  isolation: isolate;
  transition: color 0.45s var(--ease-out);
}

/* Hover blooms wine up from the base of the cell and the whole cell inverts —
   a rising field, not a line sliding across an edge. */
.servico::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(158deg, var(--vinho-mid) 0%, var(--vinho) 46%, var(--vinho-dark) 100%);
  clip-path: circle(0% at 50% 112%);
  transition: clip-path 0.62s var(--ease-out);
}
/* clip-path is a paint property — the bloom cannot be handed to the
   compositor, so it is redrawn on the main thread for its whole run. The
   hint at least warns the browser a frame ahead, and it is carried by the
   hover rule so a cell at rest asks for nothing. */
.servico:hover::before,
.servico:focus-within::before {
  clip-path: circle(142% at 50% 112%);
  will-change: clip-path;
}

.servico__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 28px;
}
.servico__icon {
  display: grid;
  place-items: center;
  width: 62px; height: 62px;
  flex-shrink: 0;
  border-radius: 19px;
  /* solid wine at rest: six of these anchor the grid so the block stops
     reading as a pale wireframe */
  background: linear-gradient(148deg, var(--vinho-mid), var(--vinho) 52%, var(--vinho-dark));
  color: var(--creme);
  box-shadow: 0 10px 22px -10px rgba(88, 19, 40, 0.55);
  transition: background 0.45s var(--ease-out),
              color 0.45s var(--ease-out),
              box-shadow 0.45s var(--ease-out),
              transform 0.55s var(--ease-out);
}
.servico__icon svg { width: 30px; height: 30px; }
.servico:hover .servico__icon {
  background: var(--creme);
  color: var(--vinho);
  box-shadow: 0 12px 26px -10px rgba(20, 4, 10, 0.5);
  transform: rotate(-6deg) scale(1.06);
}
/* the icon redraws itself, stroke by stroke */
.servico:hover .servico__icon svg > * { animation: iconDraw 0.75s var(--ease-out) both; }
.servico:hover .servico__icon svg > *:nth-child(2) { animation-delay: 0.1s; }
.servico:hover .servico__icon svg > *:nth-child(3) { animation-delay: 0.2s; }
@keyframes iconDraw {
  from { stroke-dasharray: 260; stroke-dashoffset: 260; }
  to   { stroke-dasharray: 260; stroke-dashoffset: 0; }
}

.servico__area {
  padding: 7px 14px;
  border: 1px solid var(--line-2);
  border-radius: 100px;
  font-family: var(--font-display);
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--vinho-bright);
  transition: color 0.45s var(--ease-out), border-color 0.45s var(--ease-out);
}
.servico:hover .servico__area {
  color: var(--creme);
  border-color: rgba(240, 234, 229, 0.45);
}

.servico__title {
  font-family: var(--font-display);
  font-size: 1.26rem;
  font-weight: 700;
  letter-spacing: -0.018em;
  line-height: 1.2;
  color: var(--vinho-dark);
  margin-bottom: 12px;
  transition: color 0.45s var(--ease-out);
}
.servico__text {
  font-size: 0.94rem;
  line-height: 1.72;
  color: var(--muted);
  margin-bottom: 28px;
  flex: 1;
  transition: color 0.45s var(--ease-out);
}
.servico__link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  align-self: flex-start;
  font-family: var(--font-display);
  font-size: 0.84rem;
  font-weight: 700;
  color: var(--vinho);
  transition: color 0.45s var(--ease-out), gap 0.3s var(--ease-out);
}
.servico__link .arrow { width: 15px; height: 15px; }
.servico:hover .servico__title { color: var(--creme); }
.servico:hover .servico__text  { color: rgba(240, 234, 229, 0.8); }
.servico:hover .servico__link  { color: var(--creme); gap: 14px; }
.servico:hover .servico__link .arrow { transform: translateX(4px); }
/* the whole cell is the target */
.servico__link::after { content: ''; position: absolute; inset: 0; }

/* ====================================================== DIFERENCIAL ==== */
.diferencial {
  position: relative;
  padding-block: clamp(72px, 10vw, 132px);
  padding-inline: var(--edge-l) var(--edge-r);
  background: var(--vinho);
  overflow: hidden;
  /* The section already clips. Saying so lets the browser confine the
     quote's per-frame repaint to these bounds instead of walking outwards
     to work out what else the change could have touched. */
  contain: paint;
}
.diferencial__blueprint {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* The grid never moves, but a radial mask over two repeating gradients is
     one of the more expensive things on the page to rasterise. On its own
     layer it is drawn once and re-used; sharing one with the quote meant
     redrawing it every time a word moved. */
  transform: translateZ(0);
  background:
    repeating-linear-gradient(to right,  var(--line-on-dark) 0 1px, transparent 1px 76px),
    repeating-linear-gradient(to bottom, var(--line-on-dark) 0 1px, transparent 1px 76px);
  -webkit-mask-image: radial-gradient(80% 120% at 50% 50%, #000, transparent 72%);
          mask-image: radial-gradient(80% 120% at 50% 50%, #000, transparent 72%);
  opacity: 0.6;
}
.diferencial__inner { position: relative; max-width: 940px; margin-inline: auto; }
.diferencial__quote {
  font-family: var(--font-display);
  font-size: clamp(1.45rem, 3.2vw, 2.6rem);
  font-weight: 700;
  line-height: 1.34;
  letter-spacing: -0.02em;
  text-align: center;
  color: rgba(240, 234, 229, 0.62);
}
.diferencial__quote em { font-style: normal; color: var(--creme); }

/* ========================================================= PROJETOS ==== */
.projetos { padding-block: var(--section-y); background: var(--white); }
.projetos__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: auto auto;
  gap: 24px;
}
/* The card is the hit area and never moves; __inner carries the 3D. Tilting
   the listener itself pulled its own edge off the cursor, which fired
   pointerleave, reset the transform, and re-entered — a flicker loop. */
.projeto-card {
  position: relative;
  display: grid;
  cursor: pointer;
}
.projeto-card--large { grid-column: 1 / -1; }
.projeto-card__inner {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 280px;
  border-radius: 20px;
  overflow: hidden;
  isolation: isolate;
  transform: perspective(600px)
             rotateY(calc(var(--rx, 0) * 1deg))
             rotateX(calc(var(--ry, 0) * -1deg))
             scale(var(--s, 1));
  transition: transform 0.6s var(--ease-out), box-shadow 0.4s;
}
/* While the pointer is on the card its transform is rewritten every frame,
   so the layer is claimed up front rather than being made and thrown away
   around each move. It goes with the class, so a card at rest holds
   nothing. */
.projeto-card__inner.is-tracking {
  transition: transform 0.12s ease-out, box-shadow 0.4s;
  will-change: transform;
}
.projeto-card--large .projeto-card__inner { min-height: 360px; }
.projeto-card:hover .projeto-card__inner {
  --s: 1.02;
  box-shadow: 0 24px 60px rgba(88, 19, 40, 0.2);
}

.projeto-card__bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  transition: transform 0.6s var(--ease-out);
}
.projeto-card:hover .projeto-card__bg { transform: scale(1.06); }
.projeto-card__bg--1 { background: linear-gradient(135deg, #581328 0%, #8B2042 50%, #3d0c1c 100%); }
.projeto-card__bg--2 { background: linear-gradient(135deg, #701634 0%, #581328 100%); }
.projeto-card__bg--3 { background: linear-gradient(135deg, #3d0c1c 0%, #701634 100%); }
.projeto-card__bg::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to top,
              rgba(15, 3, 7, 0.88) 0%,
              rgba(15, 3, 7, 0.55) 32%,
              rgba(15, 3, 7, 0.25) 55%,
              rgba(15, 3, 7, 0.35) 100%);
}
.projeto-card__img {
  width: 100%; height: 100%;
  object-fit: cover;
  border-radius: inherit;
  filter: brightness(0.7) saturate(0.85);
}

.projeto-card__content {
  position: relative;
  z-index: 2;
  padding: 40px;
}
.projeto-card__tag {
  width: fit-content;
  margin-bottom: 16px;
  padding: 6px 14px;
  border: 1px solid rgba(240, 234, 229, 0.3);
  border-radius: 100px;
  /* This pill used to frost its backdrop. It sits on a photo that is already
     darkened and covered by a gradient scrim, so the blur bought almost
     nothing visually — but it had to be recomputed on every frame of the
     card's tilt, once per card, which is what made the hover feel heavy.
     A little more creme in the fill reads the same and costs nothing. */
  background: rgba(240, 234, 229, 0.3);
  color: var(--creme);
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}
.projeto-card__content h3 {
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--creme);
  margin-bottom: 10px;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.65), 0 1px 2px rgba(0, 0, 0, 0.5);
}
.projeto-card__content p {
  max-width: 68ch;
  margin-bottom: 16px;
  font-size: 0.9rem;
  line-height: 1.6;
  color: rgba(240, 234, 229, 0.92);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.6);
}
.projeto-card__year {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: rgba(240, 234, 229, 0.65);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}

/* =========================================================== EQUIPE ==== */
.equipe { padding-block: var(--section-y); background: var(--creme); }

.equipe__tabs {
  /* the indicator's geometry is derived from these two, so the bar can be
     re-padded at any breakpoint without the thumb drifting off its tab */
  --tab-pad: 5px;
  --tab-gap: 4px;
  position: relative;
  /* equal columns mean the indicator never has to animate its width */
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--tab-gap);
  width: fit-content;
  max-width: 100%;
  margin: 0 auto clamp(44px, 5vw, 64px);
  padding: var(--tab-pad);
  border: 1px solid var(--line);
  border-radius: 100px;
  background: rgba(255, 255, 255, 0.6);
}
.equipe__thumb {
  position: absolute;
  top: var(--tab-pad);
  left: 0;
  /* one of three equal columns: the padding box less its own padding and
     the two gaps between the tabs */
  width: calc((100% - 2 * var(--tab-pad) - 2 * var(--tab-gap)) / 3);
  height: calc(100% - 2 * var(--tab-pad));
  border-radius: 100px;
  background: var(--vinho);
  box-shadow: 0 6px 18px rgba(88, 19, 40, 0.24);
  transition: transform 0.55s var(--ease-out);
  pointer-events: none;
}
.equipe__tab {
  position: relative;
  z-index: 1;
  padding: 11px 28px;
  border: none;
  border-radius: 100px;
  background: none;
  font-family: var(--font-display);
  font-size: 0.83rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.35s var(--ease-out);
}
.equipe__tab:hover { color: var(--vinho); }
.equipe__tab.is-active { color: var(--creme); }

/* the stage animates its own height so the swap has continuity */
.equipe__stage {
  position: relative;
  transition: height 0.5s var(--ease-out);
}
.equipe__panel { contain: layout; }
.equipe__panel[hidden] { display: none; }
.equipe__panel.is-leaving {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translate3d(0, -10px, 0);
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}
.js .equipe__panel.is-entering { opacity: 0; transform: translate3d(0, 12px, 0); }
.js .equipe__panel.is-active {
  opacity: 1;
  transform: none;
  transition: opacity 0.45s 0.1s var(--ease-out), transform 0.45s 0.1s var(--ease-out);
}

/* leadership reads as leadership */
.equipe__leads {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  max-width: 940px;
  margin-inline: auto;
}
.equipe__dirs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 255px), 1fr));
  gap: 16px;
}

.membro {
  display: flex;
  align-items: center;
  gap: 15px;
  min-width: 0;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--white);
  transition: transform 0.4s var(--ease-out),
              border-color 0.4s ease,
              box-shadow 0.4s ease;
}
.membro:hover {
  transform: translateY(-3px);
  border-color: var(--line-2);
  box-shadow: var(--shadow-sm);
}
.membro--lead {
  flex-direction: column;
  text-align: center;
  gap: 18px;
  padding: 40px 26px 32px;
}
.membro--dir { padding: 18px 20px; }

.membro__avatar {
  position: relative;
  width: 46px; height: 46px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  overflow: hidden;
  background: linear-gradient(140deg, var(--c1), var(--c2));
  box-shadow: 0 4px 14px rgba(88, 19, 40, 0.22);
}
.membro__avatar--md { width: 54px; height: 54px; }
.membro__avatar--lg { width: 116px; height: 116px; }
.membro__avatar img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ease-out);
}
.membro:hover .membro__avatar img { transform: scale(1.07); }
.membro__initials {
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  color: var(--creme);
}
.membro__avatar--md .membro__initials { font-size: 0.95rem; }
.membro__avatar--lg .membro__initials { font-size: 2rem; }

.membro__body { min-width: 0; }
.membro__name {
  font-family: var(--font-display);
  font-size: 0.9rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--vinho-dark);
}
.membro--lead .membro__name { font-size: 1.05rem; }
.membro__role {
  margin-top: 3px;
  font-size: 0.76rem;
  font-weight: 500;
  color: var(--muted);
}
.membro--lead .membro__role {
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--vinho-bright);
}

/* member areas, on rules */
.area + .area { margin-top: 40px; }
.area__head {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-bottom: 18px;
}
.area__name {
  font-family: var(--font-display);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--vinho);
  white-space: nowrap;
}
.area__rule { flex: 1; height: 1px; background: var(--line-2); }
.area__count {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.area__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 238px), 1fr));
  gap: 12px;
}

.equipe__cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 22px;
  margin-top: clamp(48px, 6vw, 72px);
  padding: clamp(30px, 4vw, 44px) clamp(26px, 4vw, 48px);
  border: 1px solid var(--line-2);
  border-radius: 12px;
  background: var(--white);
}
/* Not a button: there is nothing to click while applications are closed, so
   this is plain text in a chip. The dashed edge and the not-allowed cursor
   say "unavailable" without faking a disabled control. */
.cta-closed {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  padding: 15px 28px;
  border: 1.5px dashed var(--line-2);
  border-radius: 100px;
  background: rgba(88, 19, 40, 0.045);
  color: var(--muted);
  font-family: var(--font-display);
  font-size: 0.86rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-align: center;
  cursor: not-allowed;
  user-select: none;
}
.cta-closed__icon {
  width: 18px; height: 18px;
  flex-shrink: 0;
  color: var(--vinho-bright);
}

.equipe__cta-text {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 2.2vw, 1.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--vinho-dark);
  max-width: 22ch;
}

/* ========================================================== CONTATO ==== */
.contato { padding-block: var(--section-y); background: var(--white); }
.contato__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  grid-template-areas: "intro form" "details form";
  gap: 0 72px;
  align-items: start;
}
.contato__intro { grid-area: intro; }
.contato__form-wrap { grid-area: form; }
.contato__details { grid-area: details; }

.contato__text {
  margin-top: 22px;
  margin-bottom: 40px;
  font-size: 1.02rem;
  line-height: 1.8;
  color: var(--muted);
  max-width: 46ch;
}

/* contact rows are self-contained panels; the badge takes the ink on hover */
.contato__info { display: grid; gap: 10px; margin-bottom: 32px; }
.contato__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--creme);
  font-size: 0.93rem;
  line-height: 1.55;
  color: var(--muted);
  transition: background 0.35s var(--ease-out),
              border-color 0.35s var(--ease-out),
              transform 0.35s var(--ease-out);
}
.contato__icon {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  flex-shrink: 0;
  border-radius: 10px;
  background: rgba(88, 19, 40, 0.08);
  color: var(--vinho);
  transition: background 0.35s var(--ease-out), color 0.35s var(--ease-out);
}
.contato__icon svg { width: 19px; height: 19px; }
.contato__value { min-width: 0; font-size: 0.93rem; line-height: 1.55; }

.contato__item--action { cursor: pointer; }
.contato__item--action:hover {
  background: var(--white);
  border-color: var(--line-2);
  transform: translateX(5px);
}
.contato__item--action:hover .contato__icon { background: var(--vinho); color: var(--creme); }
.contato__item--action:hover .contato__link { color: var(--vinho-dark); }
.contato__link {
  font-weight: 500;
  transition: color 0.3s var(--ease-out);
}
/* the whole row is the target */
.contato__link::after { content: ''; position: absolute; inset: 0; }

.contato__social { display: flex; gap: 12px; }
.social {
  position: relative;
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  border: 1px solid var(--line-2);
  border-radius: 50%;
  color: var(--vinho);
  overflow: hidden;
  isolation: isolate;
  transition: color 0.35s var(--ease-out), border-color 0.35s;
}
.social::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--vinho);
  transform: scale(0);
  transition: transform 0.45s var(--ease-out);
}
.social:hover { color: var(--creme); border-color: var(--vinho); }
.social:hover::before { transform: scale(1); }
.social svg { width: 20px; height: 20px; }

/* form */
.form {
  padding: clamp(30px, 4vw, 46px);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--creme);
}
.form__group { margin-bottom: 22px; }
.form__row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; }
.form__label {
  display: block;
  margin-bottom: 9px;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--vinho-dark);
  transition: color 0.25s;
}
.form__optional { font-weight: 600; color: var(--muted); letter-spacing: 0.06em; }
.form__group:focus-within .form__label { color: var(--vinho); }

.form__input {
  width: 100%;
  padding: 14px 17px;
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: 9px;
  font-size: 0.96rem;
  color: var(--ink);
  outline: none;
  appearance: none;
  transition: border-color 0.28s var(--ease-out), box-shadow 0.28s var(--ease-out);
}
.form__input::placeholder { color: var(--muted); opacity: 1; }
.form__input:hover { border-color: var(--line-2); }
.form__input:focus {
  border-color: var(--vinho);
  box-shadow: 0 0 0 4px rgba(88, 19, 40, 0.1);
}
.form__input:focus-visible { outline: none; }
.form__input:user-invalid { border-color: var(--vinho-bright); }
.form__select {
  cursor: pointer;
  padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23581328' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
  background-size: 17px;
}
.form__textarea { min-height: 132px; resize: vertical; line-height: 1.6; }
/* off-screen without a 9999px offset — nothing to reach past the viewport */
.form__hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.form .btn { margin-top: 6px; }
.form__status {
  margin-top: 16px;
  min-height: 1.2em;
  font-size: 0.88rem;
  font-weight: 600;
  text-align: center;
  color: var(--vinho);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}
.form__status.is-shown { opacity: 1; transform: none; }
.form__status.is-error { color: var(--vinho-bright); }

/* =========================================================== FOOTER ==== */
.footer { background: var(--vinho-dark); color: rgba(240, 234, 229, 0.68); padding-top: 84px; }
.footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
  gap: 44px;
  padding-bottom: 56px;
  border-bottom: 1px solid var(--line-on-dark);
}
.footer__logo { width: 6.4rem; height: 6.4rem; object-fit: contain; margin-bottom: 18px; }
.footer__brand p { font-size: 0.87rem; line-height: 1.7; }
.footer__links h5,
.footer__contact h5 {
  margin-bottom: 18px;
  font-family: var(--font-display);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--creme);
}
.footer__links li { margin-bottom: 11px; }
.footer__links a,
.footer__contact a {
  display: inline-block;
  font-size: 0.87rem;
  color: rgba(240, 234, 229, 0.62);
  transition: color 0.25s, transform 0.35s var(--ease-out);
}
.footer__links a:hover,
.footer__contact a:hover { color: var(--creme); transform: translateX(3px); }
.footer__contact p { font-size: 0.87rem; margin-bottom: 8px; }
.footer__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 14px;
  padding-block: 26px calc(26px + env(safe-area-inset-bottom, 0px));
}
.footer__bottom p { font-size: 0.79rem; }

/* ------------------------------------------------------------ signature
   The credit is a real signature: ~2.600 points of pen path recorded from
   Fernando's own hand, written out stroke by stroke by js/assinatura.js --
   the same engine that signs the hero of his portfolio, carried over whole.

   Nothing here draws anything. This rule hands the engine three things and
   then gets out of the way: a box, how much of that box to fill, and the
   colour to write in. Both custom properties below are read back out of the
   cascade by `layout()`, which is why the ink is cream here and green there
   with no branch anywhere in the engine.                                  */
.assinatura {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 2px 2px 4px;
  color: var(--creme);
  text-decoration: none;
}
.assinatura__label {
  font-family: var(--font-display);
  font-size: 0.56rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(240, 234, 229, 0.4);
  transition: color 0.45s var(--ease-out);
}
.assinatura:hover .assinatura__label,
.assinatura:focus-visible .assinatura__label { color: rgba(240, 234, 229, 0.82); }

.assinatura-wrap {
  /* the two knobs the engine reads back */
  --assinatura-cor: var(--creme);
  --assinatura-fill: 0.98;

  display: block;
  width: clamp(168px, 19vw, 226px);
  /* the artwork's own bounding box, so the canvas needs no fudge factor and
     the fill ratio can sit at nearly 1 without clipping a single stroke */
  aspect-ratio: 1901.8 / 884;
  overflow: hidden;
}
#assinatura {
  display: block;
  width: 100%;
  height: 100%;
  background: transparent;
}

/* ======================================================= RESPONSIVE ====
   Five planned breakpoints carry the layout switches — the points where a
   composition genuinely changes shape. Everything between them is covered
   by the fluid tokens (--gutter, --section-y) and the clamp()ed type, so
   no width needs a rule of its own.
   ======================================================================== */

/* --- three-up panels become two-up ------------------------------------ */
@media (max-width: 1100px) {
  .servicos__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sobre__grid    { gap: 52px; }
  .contato__grid  { gap: 0 48px; }
  .footer__grid   { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px; }
}

/* --- the hero's two columns tighten before they break ----------------- */
@media (max-width: 960px) {
  .nav__links { gap: 22px; }
  .hero { gap: 0 32px; }
  .hero__logo-wrap { width: 200px; height: 200px; }
  .hero__logo-img { width: 132px; }
}

/* --- the nav collapses and every two-column block stacks -------------- */
@media (max-width: 820px) {
  :root { --nav-h: 66px; }

  .nav__links { display: none; }
  .nav__hamburger { display: flex; }
  .nav__logo-img { width: 2.5rem; height: 2.5rem; }
  .nav__logo-text { font-size: 1.15rem; }

  /* ------------------------------------------------------------- THE HERO
     Below 820 the two columns are gone, and with them both things that gave
     the wide hero its weight: the wine sphere and the word laid across the
     middle. The column is centred, as the rest of the page is; what carries
     it is the word, stood on its end and left behind everything as
     background, and the three readings closing the block on one rule.
     ---------------------------------------------------------------------- */
  .hero {
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* the grid rule centres on the cross axis; in a column that would
       shrink-wrap every child, so hand the width back */
    align-items: stretch;
    /* the first screen is the hero's again — it earned the height back the
       moment it had something standing in it */
    min-height: 100svh;
    padding-block: calc(var(--nav-h) + 64px) 26px;
  }

  /* The grid was lit at 68% across, which is where the sphere used to be.
     The sphere is not here and the column is centred, so the light moves to
     the middle with it. */
  .hero__blueprint {
    -webkit-mask-image: radial-gradient(155% 70% at 50% 44%, #000 6%, transparent 80%);
            mask-image: radial-gradient(155% 70% at 50% 44%, #000 6%, transparent 80%);
  }

  /* The word stands up and stays behind everything, which is the job it
     already has on a wide screen — same filled ghost, same 7%, turned a
     quarter so it has somewhere to be in a single narrow column. It runs
     the height of the screen and sits in the gutter the centred column
     leaves free, so it reads as a watermark on the page rather than as a
     column of its own that the text has to make room for. */
  .hero__bg-text {
    display: block;
    top: 50%;
    left: var(--edge-l);
    writing-mode: vertical-rl;
    font-size: clamp(58px, 17vw, 96px);
    /* Stood on its end, the line box's LEADING is what sets the column's
       width, not the glyphs — at the inherited 1.6 the word claimed half
       again the room it needed and pushed itself off the left edge. */
    line-height: 1;
    letter-spacing: 0.02em;
    transform: translate3d(0, calc(-50% + var(--drift, 0px)), 0);
  }

  .hero__visual { display: none; }
  /* The two auto margins are what place the block in the screen. Centring
     both children together left the readings stranded with a hole under
     them and the marquee a long way off; an auto above each one hands the
     spare height to the top and to the gap in equal parts instead, which
     drops the whole column and settles the readings on the bottom edge
     where they close the hero against the strip. The padding is the floor
     under that gap, for the short viewport where there is no spare height
     to hand out and both autos collapse to nothing. */
  .hero__content { margin-top: auto; padding-block: 0 24px; }

  /* The three lines are broken by hand in the markup, so not one of them
     may ever outgrow the column: a line that wraps inside its own masked
     shell comes out cut in half. The size is therefore read off the column
     rather than guessed at. 0.086 of it is what holds "com propósito", the
     longest of the three, on one line with a little air left, at every
     width from 280px up — and it keeps holding it if the page gutters are
     ever retuned, because they are in the sum. */
  .hero__title {
    font-size: clamp(1.1rem,
                     calc((100vw - var(--edge-l) - var(--edge-r)) * 0.086),
                     5rem);
    /* The deck's own leading already opens a dozen pixels under the last
       line of the title, so the margin is the remainder and not the gap. */
    margin-bottom: 8px;
  }
  /* Tight where the parts belong together, open where the reader changes
     gear: the deck sits close under the title it explains, the buttons get
     air before them because they are the turn from reading to doing, and
     the credential is far enough below to read as a footnote to all of it
     rather than as a third line of the same block. */
  .hero__subtitle {
    margin-bottom: 34px;
    font-size: 1rem;
    max-width: 40ch;
    /* four centred lines, so the last one is kept off a single orphan */
    text-wrap: pretty;
  }
  .hero__actions { margin-bottom: 32px; }
  /* two centred lines break far more evenly balanced than they do filled */
  .hero__credential { text-wrap: balance; }

  /* ---- the readings close the hero on one rule ---- */
  .hero__stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    justify-content: normal;
    margin-top: auto;
  }
  /* the reading first and its name under it, which is the order a legend is
     read in — the markup keeps the <dt> before its <dd> either way */
  .stat {
    display: flex;
    flex-direction: column-reverse;
    justify-content: flex-end;
    /* symmetric, or the centred pair sits off-centre inside its own cell */
    padding: 24px 8px 0;
  }
  .stat + .stat { padding-left: 8px; }
  .stat + .stat::before { top: 24px; height: 28px; }
  /* The block spans the sheet at every width in this range, so both sizes
     are tied to the sheet rather than pinned: on a phone the readings sit
     just above their captions, on a tablet the same block opens up with
     the page instead of leaving the strip looking undersized in it. */
  .stat__value { font-size: clamp(1.45rem, 5.8vw, 2.4rem); margin-bottom: 6px; }
  .stat__label {
    font-size: clamp(0.52rem, 1.5vw, 0.68rem);
    letter-spacing: 0.11em;
    line-height: 1.4;
    margin-bottom: 0;
  }

  .sobre__grid { grid-template-columns: minmax(0, 1fr); gap: 44px; }
  .projetos__grid { grid-template-columns: minmax(0, 1fr); }
  .projeto-card--large { grid-column: 1; }
  .projeto-card--large .projeto-card__inner { min-height: 320px; }
  .projeto-card__content { padding: clamp(22px, 5vw, 40px); }

  .equipe__leads { grid-template-columns: minmax(0, 1fr); max-width: 420px; }
  .equipe__cta { flex-direction: column; align-items: stretch; }
  .cta-closed { justify-content: center; }

  .contato__grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "intro" "form" "details";
    gap: 40px;
  }
  .footer { padding-top: 60px; }
  /* the brand block keeps the full width; the two link lists pair up */
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 34px 28px; }
  .footer__brand { grid-column: 1 / -1; }
  .footer__bottom { flex-direction: column; text-align: center; }
}

/* --- the stacked composition centres ----------------------------------
   Once every section is a single column there is no second column for a
   left-aligned edge to align WITH, so the ragged edge stops reading as
   structure. Half of this cannot be done with text-align: the hero actions,
   the contact rows, the member cards and the menu links are flex rows whose
   boxes have to be centred, and the capped measures need their auto margins
   back. Two things deliberately stay as they are: the nav (logo left,
   burger right) and the form, whose labels are easier to tie to their
   fields on the left.
   ---------------------------------------------------------------------- */
@media (max-width: 820px) {
  .hero__content,
  /* a sibling of .hero__content, not a child — it inherits nothing from it */
  .hero__stats,
  .section-head,
  .sobre__left,
  .servico,
  .membro,
  .area__grid,
  .projeto-card__content,
  .equipe__cta,
  .contato__intro,
  .contato__details,
  .footer__grid { text-align: center; }

  /* capped measures were anchored left by their column; hand back the auto
     margins so they centre on the new axis */
  .section-title,
  .section-sub,
  .sobre__text,
  .hero__subtitle,
  .contato__text,
  .equipe__cta-text,
  .projeto-card__content p,
  .projeto-card__tag,
  .footer__logo { margin-inline: auto; }

  /* flex rows: text-align cannot move these, only the box distribution can */
  .hero__actions,
  .hero__credential,
  .servico__head,
  .membro,
  .contato__social,
  .mobile-link { justify-content: center; }

  .servico__link { align-self: center; }

  /* a lead-in rule on one side only reads as a lead-in while the line is
     ragged left; centred, it just looks like a stray dash */
  .hero__credential-rule { display: none; }

  /* The three contact rows keep their left-aligned icon + value pair. They
     are stacked panels of equal width, so their own left edge is the second
     column a centred row would have nothing to align with. */
  .contato__item { text-align: start; }

  /* a sideways slide on hover reads as a misalignment once the row is
     centred, so the centred footer links deepen without travelling */
  .footer__links a:hover,
  .footer__contact a:hover { transform: none; }
}

/* --- phones: the last multi-column blocks fold ------------------------ */
@media (max-width: 700px) {
  .servicos__grid { grid-template-columns: minmax(0, 1fr); }
  .footer__grid { grid-template-columns: minmax(0, 1fr); }
  /* in one column the brand reads as a sign-off, so it follows the link
     lists and the contact block instead of heading them */
  .footer__brand { grid-column: auto; order: 1; }
}

/* --- small phones ----------------------------------------------------- */
@media (max-width: 520px) {
  /* The title block keeps its three columns all the way down. Stacked, the
     three readings became three full-width rows and spent half the screen
     saying 2, 29 and 2; what gives instead is the type inside them. */
  .stat { padding: 20px 5px 0; }
  .stat + .stat { padding-left: 6px; }
  .stat__label { font-size: 0.5rem; letter-spacing: 0.07em; }

  .hero__credential { font-size: 0.64rem; letter-spacing: 0.1em; }

  /* the label needs two lines this narrow, so the pill becomes a rounded
     rectangle — a stadium shape stretched over two lines reads broken */
  .cta-closed {
    padding: 14px 20px;
    font-size: 0.79rem;
    line-height: 1.45;
    border-radius: 16px;
  }
  .equipe__tabs { width: 100%; }
  .equipe__tab { padding: 11px 6px; font-size: 0.72rem; letter-spacing: 0.01em; }

  .servico { padding: 30px 24px; }
  .membro--lead { padding: 32px 20px 26px; }
  .membro__avatar--lg { width: 96px; height: 96px; }
  .form { padding: 26px 20px; }
  .form__row { grid-template-columns: minmax(0, 1fr); gap: 0; }
}

/* =============================================== ORIENTATION & INPUT ====
   Not width: these ask what the device can actually do.
   ======================================================================== */

/* A phone or tablet held sideways has width to spare and almost no height,
   so the vertical rhythm — not the columns — is what has to give. */
@media (orientation: landscape) and (max-height: 560px) {
  :root { --section-y: clamp(56px, 13vh, 96px); }
  .hero { min-height: auto; padding-block: calc(var(--nav-h) + 32px) 0; }
  .hero__content { padding-block: 24px; }
  .hero__logo-wrap { width: 168px; height: 168px; }
  .hero__logo-img { width: 112px; }
  .mobile-link { padding-block: 11px; font-size: clamp(1.05rem, 5.2vh, 1.8rem); }
  .equipe__cta { margin-top: clamp(32px, 6vh, 56px); }
}

/* Touch. Two things break silently here: targets sized for a cursor, and
   any input under 16px, which makes iOS Safari zoom the page on focus and
   never zoom back. */
@media (pointer: coarse) {
  /* ------------------------------------------- the flat versions
     Nothing below changes a single pixel. Every rule here replaces a
     transform that CONTAINS a 3D function with the 2D transform it already
     evaluates to on a touch device — and a 3D function is what makes a
     browser hold a compositor layer for the element forever, whether or not
     the transform actually does anything.

     That mattered here because this page ends up holding a lot of them at
     once: three project cards the size of the screen, the hero mark, and one
     per word across six split headings. On a phone those are tens of
     megabytes of texture that Safari has to keep, and when it runs short it
     drops them and rasterises again mid-scroll — which is the stutter that
     has nothing to do with how much work the frame is doing. */

  /* The tilt binds only where the pointer is fine (see syncTilt in
     js/main.js), so on a touch screen --rx and --ry are never written and
     both rotations are permanently 0deg. A perspective with nothing rotated
     inside it is the identity: `scale()` alone is the same matrix, and the
     hover scale still composes through --s exactly as before. */
  .hero__logo-3d,
  .projeto-card__inner { transform: scale(var(--s, 1)); }

  /* The masked rise, in 2D. The travel is identical — 120% of the line box,
     same easing, same stagger — but the word lets its layer go once it has
     landed instead of keeping one for the rest of the session. iOS draws
     text with grayscale antialiasing either way, so the settled word is
     rasterised exactly as it was. */
  .js .ln__i, .js .w__i { transform: translateY(120%); }
  .js .is-in .ln__i,
  .js .is-in .w__i,
  .js .hero.is-ready .ln__i { transform: translateY(0); }

  .form__input { font-size: 1rem; }
  .footer__links a,
  .footer__contact a { padding-block: 7px; }
  .footer__links li { margin-bottom: 3px; }
  .footer__contact p { margin-bottom: 2px; }
  .equipe__tab { padding-block: 14px; }
  .servico__link { padding-block: 6px; }
  .assinatura { padding-block: 8px 12px; }
  .social { width: 50px; height: 50px; }
}

/* Without a pointer, :hover latches on tap — which would park the marquee
   for good. Nothing else here is hover-only: every hover in this sheet
   deepens something already legible at rest. */
@media (hover: none) {
  .marquee:hover .marquee__inner { animation-play-state: running; }
}

/* =================================================== REDUCED MOTION ====
   Tiered, not blanket: spatial movement and loops go, state and feedback
   transitions stay legible.                                              */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  /* keep the fade, drop the travel */
  .js [data-reveal] { translate: none; }
  .js [data-reveal].is-in { animation: revealFade 0.4s ease both; }
  @keyframes revealFade { from { opacity: 0; } to { opacity: 1; } }
  .js .ln__i, .js .w__i,
  .js .is-in .ln__i, .js .is-in .w__i { transform: none; transition: none; }
  .ln, .w { overflow: visible; }

  .js .hero__subtitle, .js .hero__actions, .js .hero__credential, .js .stat,
  .js .hero__logo-wrap { transform: none; }

  /* no loops at all */
  .marquee__inner,
  .hero__logo-float,
  .pilar:hover .pilar__mark svg > *,
  .servico:hover .servico__icon svg > * { animation: none !important; }

  /* no pointer-driven movement */
  .hero__logo-3d, .projeto-card__inner { transform: none !important; }
  .membro:hover, .pilar:hover, .contato__item--action:hover { transform: none; }
  .pilar:hover .pilar__mark, .servico:hover .servico__icon { transform: none; }
  .pilar:hover::before { animation: none; opacity: 1; }
  .js [data-scrub] .w__i { transform: none !important; }
  .servico::before { transition: none; }

  .mobile-menu { transition: opacity 0.2s ease, visibility 0.2s; clip-path: none; }
  .mobile-menu.is-open { clip-path: none; }
  .mobile-link { transform: none; }

  /* The engine already handles this one itself: `prefers-reduced-motion`
     makes it paint the finished signature in a single frame instead of
     writing it. Nothing to override here -- and nothing to hide, because a
     signature that is not animated is still a signature. */

  /* feedback that must survive */
  .btn.is-sending .btn__spinner { animation: spin 0.9s linear infinite; }
}
