@import url('./fonts.css');

/* ==========================================================================
   Joaquim Pinto e Filhos — serviços florestais, Marinha Grande / Leiria
   --------------------------------------------------------------------------
   The two greens are the company's own, sampled from their logo. Everything else
   is built around them: the darker grounds extend that same hue downward, the bone
   ground keeps the greens legible, and hi-vis orange — the colour of the crew's
   helmets and saws — carries action and urgency. Orange never touches the light
   green (1.53:1); it lives on bone or on bark.

   Type is tight and industrial; corners are near-square. The one recurring motif
   is a clipped corner (--cut), which reads as a cut edge.

   Colour pairs are verified by scripts/check-contrast.js. If you change a colour,
   re-run it. Two traps it exists to catch:
     - safety-500 is NOT for text on light (3.46:1) — safety-600 is (5.38:1).
     - moss-500 (brand light green) is NOT for text on light at all (2.26:1). It is
       a dark-ground and graphic colour only.
   ========================================================================== */

/* ---------- Tokens ---------- */

:root {
  /* Palette — primitives. Don't reference these directly in components.
     The two greens are sampled from the company's own logo: #2E5525 ("&FILHOS",
     trunk) and #76B637 ("JOAQUIM PINTO", canopy). The darker grounds are extended
     down from that same hue rather than invented, so the photography, the logo and
     the UI all sit on one green. */
  --bark-950: #101c0c;
  --bark-900: #17280f;
  --bark-800: #20361a;
  --forest-700: #2e5525; /* brand dark green */
  --forest-600: #3a6b2f;
  --moss-500: #76b637; /* brand light green — 2.26:1 on bone, NEVER text on light */
  --bone-50: #f7f5f0;
  --bone-100: #efebe3;
  --bone-200: #e3ddd1;
  --ink: #101a14;
  --ink-muted: #55635a;
  --safety-500: #e2560d;
  /* safety-600 is the text-weight accent. It must clear 4.5:1 on the DARKEST light
     surface, which is --bg-alt (bone-100), not bone-50 — an earlier #c2470a passed
     on bone-50 at 4.59 but failed on bone-100 at 4.21. */
  --safety-600: #b04008;
  --safety-300: #f79b5c;
  --white: #fff;

  /* Semantic tokens — components use these. */
  --bg: var(--bone-50);
  --bg-alt: var(--bone-100);
  --surface: var(--white);
  --surface-sunk: var(--bone-100);
  --fg: var(--ink);
  --fg-muted: var(--ink-muted);
  --primary: var(--forest-700);
  --primary-hover: var(--forest-600);
  --on-primary: var(--white);
  --accent: var(--safety-500);
  --accent-text: var(--safety-600);
  --on-accent: var(--bark-950);
  --border: var(--bone-200);
  --border-strong: #cfc7b6;
  --ring: var(--safety-600);
  --danger: #b42318;

  /* Inverted surfaces (hero, bands, footer) keep their own tokens so components
     placed on them don't need to know which mode the page is in. */
  --inv-bg: var(--bark-950);
  --inv-surface: var(--bark-900);
  --inv-fg: var(--bone-50);
  --inv-fg-muted: var(--bone-200);
  --inv-border: #2b3d20;

  /* Type */
  --font-display: 'Archivo', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-body: 'Archivo', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Fluid type scale. Body lands at 16px on mobile (below that iOS zooms on
     input focus) and 17px on desktop. */
  --step--2: clamp(0.6875rem, 0.67rem + 0.09vw, 0.75rem);
  --step--1: clamp(0.8125rem, 0.79rem + 0.11vw, 0.875rem);
  --step-0: clamp(1rem, 0.98rem + 0.11vw, 1.0625rem);
  --step-1: clamp(1.125rem, 1.09rem + 0.18vw, 1.25rem);
  --step-2: clamp(1.375rem, 1.3rem + 0.36vw, 1.625rem);
  --step-3: clamp(1.625rem, 1.5rem + 0.63vw, 2.0625rem);
  --step-4: clamp(2rem, 1.78rem + 1.07vw, 2.75rem);
  --step-5: clamp(2.375rem, 1.98rem + 1.96vw, 3.75rem);
  --step-6: clamp(2.75rem, 1.98rem + 3.75vw, 5rem);

  /* Space — 4px rhythm */
  --space-2xs: 0.25rem;
  --space-xs: 0.5rem;
  --space-s: 0.75rem;
  --space-m: 1rem;
  --space-l: 1.5rem;
  --space-xl: 2rem;
  --space-2xl: 3rem;
  --space-3xl: 4rem;
  --space-4xl: 6rem;
  --section-y: clamp(3.5rem, 8vw, 7.5rem);
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --container: 78rem;
  --measure: 68ch;

  /* Shape — near-square. This trade is not soft. */
  --radius-xs: 2px;
  --radius-sm: 3px;
  --radius: 5px;
  --radius-lg: 8px;
  --cut: 14px; /* clipped-corner motif */

  /* Elevation — restrained; the style is flat, shadows only lift real overlays. */
  --shadow-sm: 0 1px 2px rgb(16 28 12 / 6%), 0 1px 3px rgb(16 28 12 / 4%);
  --shadow-md: 0 4px 12px rgb(16 28 12 / 8%), 0 2px 4px rgb(16 28 12 / 4%);
  --shadow-lg: 0 12px 32px rgb(16 28 12 / 14%), 0 4px 8px rgb(16 28 12 / 6%);

  /* Motion. One rhythm for the whole site. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 150ms;
  --dur: 240ms;
  --dur-slow: 420ms;

  /* Layers */
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 40;
  --z-header: 60;
  --z-overlay: 80;
  --z-modal: 100;
}

/* Dark mode. Not an inversion: the bark greens are already the dark end of the
   brand, so dark mode promotes them to the page ground and lightens the accent
   (safety-500 on bark only reaches 4.86:1, so text-weight accent uses safety-300). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --bg: var(--bark-950);
    --bg-alt: var(--bark-900);
    --surface: var(--bark-900);
    --surface-sunk: #0b1508;
    --fg: var(--bone-50);
    --fg-muted: #a9b69f;
    --primary: var(--moss-500);
    --primary-hover: #8cc94f;
    --on-primary: var(--bark-950);
    --accent: var(--safety-500);
    --accent-text: var(--safety-300);
    --border: #2b3d20;
    --border-strong: #3d5433;
    --ring: var(--safety-300);
    --danger: #f97066;
    --inv-bg: #080f05;
    --inv-surface: var(--bark-900);
    --shadow-sm: 0 1px 2px rgb(0 0 0 / 40%);
    --shadow-md: 0 4px 12px rgb(0 0 0 / 45%);
    --shadow-lg: 0 12px 32px rgb(0 0 0 / 55%);
  }
}

:root[data-theme='dark'] {
  --bg: var(--bark-950);
  --bg-alt: var(--bark-900);
  --surface: var(--bark-900);
  --surface-sunk: #0b1508;
  --fg: var(--bone-50);
  --fg-muted: #a9b69f;
  --primary: var(--moss-500);
  --primary-hover: #8cc94f;
  --on-primary: var(--bark-950);
  --accent-text: var(--safety-300);
  --border: #2b3d20;
  --border-strong: #3d5433;
  --ring: var(--safety-300);
  --danger: #f97066;
  --inv-bg: #080f05;
  --inv-surface: var(--bark-900);
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 40%);
  --shadow-md: 0 4px 12px rgb(0 0 0 / 45%);
  --shadow-lg: 0 12px 32px rgb(0 0 0 / 55%);
}

/* ---------- Reset ---------- */

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

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Offset for the sticky header when jumping to an anchor. */
  scroll-padding-top: 5.5rem;
}

body {
  min-height: 100dvh;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

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

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

p,
li {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

/* Focus: never removed, always visible on both grounds. */
:focus-visible {
  outline: 3px solid var(--ring);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

.on-dark :focus-visible,
.hero :focus-visible,
.footer :focus-visible {
  outline-color: var(--safety-300);
}

::selection {
  background: var(--safety-500);
  color: var(--bark-950);
}

/* ---------- Layout primitives ---------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--narrow {
  max-width: 58rem;
}

.section {
  padding-block: var(--section-y);
  position: relative;
}

.section--alt {
  background: var(--bg-alt);
}

.section--dark {
  background: var(--inv-bg);
  color: var(--inv-fg);
}

.stack > * + * {
  margin-block-start: var(--flow, var(--space-m));
}

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

.skip-link {
  position: absolute;
  top: 0;
  left: var(--space-m);
  z-index: var(--z-modal);
  padding: var(--space-s) var(--space-m);
  background: var(--safety-500);
  color: var(--bark-950);
  font-weight: 700;
  text-decoration: none;
  border-radius: 0 0 var(--radius) var(--radius);
  transform: translateY(-110%);
  transition: transform var(--dur) var(--ease-out);
}

.skip-link:focus {
  transform: translateY(0);
}

/* ---------- Type helpers ---------- */

.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.eyebrow::before {
  content: '';
  inline-size: 1.75rem;
  block-size: 2px;
  background: var(--accent);
  flex: none;
}

.section--dark .eyebrow,
.on-dark .eyebrow {
  color: var(--safety-300);
}

.section-head {
  max-width: 46rem;
  margin-block-end: clamp(2rem, 5vw, 3.5rem);
}

.section-head > * + * {
  margin-block-start: var(--space-m);
}

.section-title {
  font-size: var(--step-4);
}

.lead {
  font-size: var(--step-1);
  color: var(--fg-muted);
  max-width: var(--measure);
  line-height: 1.55;
}

.section--dark .lead,
.on-dark .lead {
  color: var(--inv-fg-muted);
}

.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ---------- Buttons ---------- */

.btn {
  --btn-bg: var(--primary);
  --btn-fg: var(--on-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  min-block-size: 3rem; /* >= 44px touch target */
  padding: 0.8rem 1.4rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-align: center;
  text-decoration: none;
  border-radius: var(--radius);
  cursor: pointer;
  /* Only transform/opacity/colour animate — no layout properties. */
  transition:
    background-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
  touch-action: manipulation;
}

.btn:hover {
  background: var(--primary-hover);
}

.btn:active {
  transform: translateY(1px) scale(0.99);
}

.btn__icon {
  inline-size: 1.15em;
  block-size: 1.15em;
  flex: none;
}

.btn--accent {
  --btn-bg: var(--safety-500);
  --btn-fg: var(--bark-950);
  box-shadow: var(--shadow-sm);
}

.btn--accent:hover {
  --btn-bg: #f1691f;
}

.btn--lg {
  min-block-size: 3.5rem;
  padding: 1rem 1.75rem;
  font-size: var(--step-1);
}

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--fg);
  border: 1.5px solid var(--border-strong);
}

.btn--ghost:hover {
  background: var(--surface-sunk);
}

.on-dark .btn--ghost,
.hero .btn--ghost {
  --btn-fg: var(--inv-fg);
  border-color: rgb(247 245 240 / 35%);
}

.on-dark .btn--ghost:hover,
.hero .btn--ghost:hover {
  background: rgb(247 245 240 / 10%);
  border-color: rgb(247 245 240 / 60%);
}

.btn--block {
  inline-size: 100%;
}

.btn[disabled],
.btn[aria-disabled='true'] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.btn__spinner {
  inline-size: 1.1em;
  block-size: 1.1em;
  border: 2px solid currentcolor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 700ms linear infinite;
}

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

/* ---------- Link with arrow ---------- */

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  color: var(--accent-text);
  font-weight: 600;
  text-decoration: none;
}

.link-arrow svg {
  inline-size: 1em;
  block-size: 1em;
  transition: transform var(--dur) var(--ease-out);
}

.link-arrow:hover svg {
  transform: translateX(4px);
}

.link-arrow:hover {
  text-decoration: underline;
}

/* ---------- Header ---------- */

.header {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: var(--z-header);
  transition:
    background-color var(--dur) var(--ease-out),
    box-shadow var(--dur) var(--ease-out),
    transform var(--dur) var(--ease-out);
}

/* Over the hero the header is transparent; once scrolled past it gains a ground.
   JS toggles .is-stuck rather than CSS alone so the hero can stay dark-on-dark. */
.header.is-stuck {
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px) saturate(1.4);
  box-shadow: 0 1px 0 var(--border);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-l);
  block-size: 4.5rem;
}

/* The real logo lockup, as two raster variants derived from the company's own
   artwork. Two <img>s rather than one recoloured file: their mark is two-tone
   (light green + dark green) and there is no single colouring that survives both
   a bone and a bark ground. --logo-light is shown over the hero/footer; --logo-dark
   once the header gains its solid ground. */
.logo {
  display: inline-flex;
  align-items: center;
  flex: none;
  text-decoration: none;
  line-height: 0;
}

.logo img {
  inline-size: auto;
  block-size: 2.5rem;
}

@media (min-width: 48rem) {
  .logo img {
    block-size: 2.75rem;
  }
}

/* Swap the variant based on the ground rather than toggling opacity on both, so
   only one is ever painted. */
.logo__on-dark {
  display: block;
}

.logo__on-light {
  display: none;
}

.header.is-stuck .logo__on-dark {
  display: none;
}

.header.is-stuck .logo__on-light {
  display: block;
}

/* In dark mode the stuck header is itself dark, so keep the light-ground variant. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .header.is-stuck .logo__on-dark {
    display: block;
  }

  :root:not([data-theme='light']) .header.is-stuck .logo__on-light {
    display: none;
  }
}

:root[data-theme='dark'] .header.is-stuck .logo__on-dark {
  display: block;
}

:root[data-theme='dark'] .header.is-stuck .logo__on-light {
  display: none;
}

.nav {
  display: none;
}

/* The middle (vw) term is what governs the gap just above the desktop breakpoint —
   the clamp only reaches its lower bound at widths where the nav is already hidden.
   Portuguese is the binding case: its labels and its CTA ("Solicitar orçamento") run
   longer than the English, and at 1.6vw the row cleared the container by only 11px.
   1.35vw restores a usable margin without visibly tightening wide screens. */
.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(0.6rem, 1.35vw, 1.75rem);
  list-style: none;
  padding: 0;
}

.nav__link {
  color: var(--inv-fg);
  font-size: var(--step--1);
  font-weight: 500;
  text-decoration: none;
  padding-block: 0.5rem;
  position: relative;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out);
}

.header.is-stuck .nav__link {
  color: var(--fg);
}

.nav__link::after {
  content: '';
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  inline-size: 100%;
  block-size: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease-out);
}

.nav__link:hover::after,
.nav__link[aria-current='true']::after {
  transform: scaleX(1);
  transform-origin: left;
}

.header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  flex: none;
}

/* Language switcher */
.lang {
  display: flex;
  align-items: center;
  border: 1.5px solid rgb(247 245 240 / 30%);
  border-radius: var(--radius);
  overflow: hidden;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
}

.header.is-stuck .lang {
  border-color: var(--border-strong);
}

/* Sized to a comfortable target rather than to the text: at 0.4rem padding these
   came out 31x24, which clears WCAG 2.2's 24px floor but is a fiddly tap on a
   phone. min-block-size does the work without stretching the pill horizontally. */
.lang__item {
  display: inline-flex;
  align-items: center;
  min-block-size: 2.5rem;
  padding-inline: 0.7rem;
  color: var(--inv-fg);
  text-decoration: none;
  text-transform: uppercase;
  line-height: 1;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.header.is-stuck .lang__item {
  color: var(--fg);
}

.lang__item[aria-current='true'] {
  background: var(--safety-500);
  color: var(--bark-950);
}

.lang__item:not([aria-current='true']):hover {
  background: rgb(247 245 240 / 15%);
}

.header.is-stuck .lang__item:not([aria-current='true']):hover {
  background: var(--surface-sunk);
}

.header__cta {
  display: none;
}

.burger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  color: var(--inv-fg);
  border: 1.5px solid rgb(247 245 240 / 30%);
  border-radius: var(--radius);
  flex: none;
}

.header.is-stuck .burger {
  color: var(--fg);
  border-color: var(--border-strong);
}

.burger svg {
  inline-size: 1.25rem;
  block-size: 1.25rem;
}

/* 64rem, not 62rem. The formal nav labels are longer than the ones they replaced, and
   at ~985px the row (logo + nav + language switcher + "Solicitar orçamento") no longer
   fitted — the CTA was pushed outside the container and clipped by the body's
   overflow-x. Below this width the burger handles it. */
@media (min-width: 64rem) {
  .nav {
    display: block;
  }

  .burger {
    display: none;
  }

  .header__cta {
    display: inline-flex;
  }
}

/* ---------- Mobile menu ---------- */

.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  grid-template-rows: auto 1fr auto;
  background: var(--inv-bg);
  color: var(--inv-fg);
  padding: var(--space-m) var(--gutter) max(var(--space-xl), env(safe-area-inset-bottom));
  /* Closed state: not just hidden, but removed from the a11y tree and hit-testing. */
  visibility: hidden;
  opacity: 0;
  transform: translateY(-1rem);
  transition:
    opacity var(--dur) var(--ease-out),
    transform var(--dur) var(--ease-out),
    visibility 0s linear var(--dur);
}

.menu.is-open {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition-delay: 0s;
}

.menu__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  block-size: 4.5rem;
}

.menu__list {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-xs);
  list-style: none;
  padding: 0;
  margin: 0;
}

.menu__link {
  display: block;
  padding: var(--space-s) 0;
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 700;
  letter-spacing: -0.03em;
  text-decoration: none;
  border-block-end: 1px solid var(--inv-border);
  /* Staggered entrance; --i is set inline per item. */
  opacity: 0;
  transform: translateY(0.75rem);
}

.menu.is-open .menu__link {
  animation: menu-in var(--dur-slow) var(--ease-out) forwards;
  animation-delay: calc(60ms + var(--i, 0) * 40ms);
}

@keyframes menu-in {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.menu__foot {
  display: grid;
  gap: var(--space-s);
}

.menu__phone {
  font-family: var(--font-mono);
  font-size: var(--step-1);
  color: var(--safety-300);
  text-decoration: none;
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-block-size: 100svh;
  padding-block: 8rem var(--space-3xl);
  background: var(--bark-950);
  color: var(--inv-fg);
  overflow: clip;
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero__img {
  /* Sizing comes from .media img. The photo is a ground, not the subject —
     desaturate it slightly so the orange accent stays the only saturated thing
     on screen. */
  filter: saturate(0.75) contrast(1.05);
}

/* Two-part scrim: a vertical wash, plus a strong left-to-right wash that beds the
   copy column.

   These stops are not eyeballed — they were solved against the actual composited
   pixels of the hero photo (canvas sample of image + both gradients, worst pixel in
   each text element's box). The first attempt used a 55% left wash and measured
   3.9:1 behind the lead and 2.5:1 behind the eyebrow — the bright fog in this
   particular photo eats a weak scrim. Current worst cases:
     title  7.5:1   accent line 3.9:1 (large, needs 3)
     lead   5.8:1   trust list  8.3:1
   If you swap the hero photo, re-run that measurement; a brighter image will need
   more here. */
.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      to top,
      rgb(16 28 12 / 96%) 0%,
      rgb(16 28 12 / 90%) 22%,
      rgb(16 28 12 / 62%) 52%,
      rgb(16 28 12 / 45%) 78%,
      rgb(16 28 12 / 55%) 100%
    ),
    linear-gradient(
      to right,
      rgb(16 28 12 / 94%) 0%,
      rgb(16 28 12 / 90%) 40%,
      rgb(16 28 12 / 62%) 62%,
      rgb(16 28 12 / 22%) 85%,
      rgb(16 28 12 / 30%) 100%
    );
}

/* The eyebrow is 11px. Orange at that size over a photo measured 4.0:1 even under
   the strengthened scrim — short of the 4.5 that small text needs. Light text keeps
   it legible; the orange rule keeps the brand signal, and as a purely decorative
   graphic it isn't bound by the text threshold. On solid grounds elsewhere the
   eyebrow stays orange. */
.hero .eyebrow {
  color: var(--inv-fg);
}

.hero .eyebrow::before {
  background: var(--safety-300);
}

.hero__inner {
  position: relative;
  z-index: 1;
  inline-size: 100%;
}

.hero__grid {
  display: grid;
  gap: var(--space-2xl);
  align-items: end;
}

.hero__title {
  font-size: var(--step-6);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 0.95;
  margin-block: var(--space-m) var(--space-l);
  max-width: 15ch;
}

.hero__title em {
  display: block;
  font-style: normal;
  color: var(--safety-300);
}

.hero__lead {
  font-size: var(--step-1);
  color: var(--inv-fg-muted);
  max-width: 46ch;
  line-height: 1.55;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin-block-start: var(--space-xl);
}

.hero__trust {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s) var(--space-l);
  list-style: none;
  padding: 0;
  margin-block-start: var(--space-xl);
  font-size: var(--step--1);
  color: var(--inv-fg-muted);
}

.hero__trust li {
  display: flex;
  align-items: center;
  gap: 0.45rem;
}

.hero__trust svg {
  inline-size: 1.05rem;
  block-size: 1.05rem;
  color: var(--safety-300);
  flex: none;
}

@media (min-width: 62rem) {
  .hero__grid {
    grid-template-columns: 1.35fr 1fr;
    gap: var(--space-3xl);
  }
}

/* ---------- Compliance banner (state-aware) ---------- */

/* This is the site's sharpest tool. It reads the deadline from config and renders
   one of three states, so it can never show an expired countdown. */
.compliance {
  position: relative;
  border: 1px solid var(--inv-border);
  border-radius: var(--radius-lg);
  background: rgb(18 33 26 / 82%);
  backdrop-filter: blur(8px);
  padding: var(--space-l);
  /* Cut-corner motif. */
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%);
}

.compliance::before {
  content: '';
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 3px;
  background: var(--state-color, var(--safety-500));
}

.compliance[data-state='after'] {
  --state-color: #e8543f;
}

.compliance[data-state='before'] {
  --state-color: var(--safety-500);
}

.compliance[data-state='today'] {
  --state-color: #e8543f;
}

.compliance__label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--inv-fg-muted);
}

.compliance__dot {
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  background: var(--state-color);
  flex: none;
  animation: pulse 2.4s var(--ease-in-out) infinite;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.45;
    transform: scale(0.82);
  }
}

.compliance__title {
  font-size: var(--step-2);
  margin-block: var(--space-s) var(--space-xs);
  color: var(--inv-fg);
}

.compliance__count {
  font-family: var(--font-mono);
  font-size: var(--step-5);
  font-weight: 500;
  line-height: 1;
  color: var(--safety-300);
  font-variant-numeric: tabular-nums;
}

.compliance__body {
  font-size: var(--step--1);
  color: var(--inv-fg-muted);
  line-height: 1.5;
}

.compliance__note {
  display: flex;
  gap: var(--space-xs);
  margin-block-start: var(--space-m);
  padding-block-start: var(--space-m);
  border-block-start: 1px solid var(--inv-border);
  font-size: var(--step--2);
  color: var(--inv-fg-muted);
  line-height: 1.5;
}

.compliance__note svg {
  inline-size: 1rem;
  block-size: 1rem;
  color: var(--safety-300);
  flex: none;
  margin-block-start: 0.15em;
}

.compliance__cta {
  margin-block-start: var(--space-m);
}

.compliance__fines {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--inv-fg-muted);
  margin-block-start: var(--space-s);
}

/* ---------- Stats ---------- */

.stats {
  border-block: 1px solid var(--border);
  background: var(--surface);
}

.stats__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

.stats__item {
  padding: var(--space-xl) var(--space-m);
  text-align: center;
  border-inline-end: 1px solid var(--border);
  border-block-end: 1px solid var(--border);
}

.stats__item:nth-child(2n) {
  border-inline-end: 0;
}

.stats__item:nth-child(n + 3) {
  border-block-end: 0;
}

.stats__value {
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--primary);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.stats__label {
  font-size: var(--step--1);
  color: var(--fg-muted);
  margin-block-start: var(--space-xs);
}

@media (min-width: 48rem) {
  .stats__grid {
    grid-template-columns: repeat(4, 1fr);
  }

  .stats__item {
    border-block-end: 0;
  }

  .stats__item:nth-child(2n) {
    border-inline-end: 1px solid var(--border);
  }

  .stats__item:last-child {
    border-inline-end: 0;
  }
}

/* ---------- Service cards ---------- */

.services__grid {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) {
  .services__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 64rem) {
  .services__grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition:
    transform var(--dur) var(--ease-out),
    box-shadow var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: var(--border-strong);
}

.card__media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--surface-sunk);
}

.card__img {
  transition: transform var(--dur-slow) var(--ease-out);
}

.card:hover .card__img {
  transform: scale(1.05);
}

.card__badge {
  position: absolute;
  inset-block-start: var(--space-s);
  inset-inline-start: var(--space-s);
  padding: 0.3rem 0.6rem;
  background: var(--safety-500);
  color: var(--bark-950);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: var(--radius-xs);
}

.card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: var(--space-l);
  gap: var(--space-s);
}

.card__title {
  font-size: var(--step-2);
  letter-spacing: -0.025em;
}

.card__short {
  color: var(--accent-text);
  font-size: var(--step--1);
  font-weight: 600;
}

.card__text {
  color: var(--fg-muted);
  font-size: var(--step--1);
  line-height: 1.55;
}

.card__points {
  list-style: none;
  padding: 0;
  margin-block-start: auto;
  padding-block-start: var(--space-m);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

.card__point {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.5rem;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--fg-muted);
}

/* The whole card is clickable via a stretched pseudo-element on the title link,
   which keeps a single tab stop and a real link target for screen readers. */
.card__link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}

.card__link {
  text-decoration: none;
  color: inherit;
}

/* ---------- Process ---------- */

.process__grid {
  display: grid;
  gap: var(--space-l);
  counter-reset: step;
}

@media (min-width: 48rem) {
  .process__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 68rem) {
  .process__grid {
    /* Column count follows the actual number of steps (set inline as --steps),
       rather than a hardcoded 4 that leaves an empty cell when a step is removed. */
    grid-template-columns: repeat(var(--steps, 4), 1fr);
  }
}

.step {
  position: relative;
  padding-block-start: var(--space-l);
  border-block-start: 2px solid var(--border-strong);
  counter-increment: step;
}

/* The marker dot sits on the top rule and reads as a progress track on desktop. */
.step::before {
  content: '';
  position: absolute;
  inset-block-start: -6px;
  inset-inline-start: 0;
  inline-size: 10px;
  block-size: 10px;
  background: var(--accent);
  border-radius: 50%;
}

.step__num {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--accent-text);
}

.step__num::before {
  content: '0' counter(step);
}

.step__title {
  font-size: var(--step-2);
  margin-block: var(--space-xs) var(--space-s);
}

.step__body {
  color: var(--fg-muted);
  font-size: var(--step--1);
  line-height: 1.55;
}

/* ---------- Service card: no photo yet ---------- */

/* Two of the seven services have no photograph. Rather than pad them with a stock
   stand-in (which would be the only inauthentic image on the page) or leave a grey
   hole, the card leads with its icon on a brand-green ground. It reads as a
   deliberate variant, not an omission. */
.card__media--icon {
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at 30% 25%, rgb(118 182 55 / 22%), transparent 60%),
    var(--forest-700);
  position: relative;
}

.card__media--icon::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Faint diagonal hatch — echoes the cut-corner motif and stops the panel reading
     as a flat placeholder. */
  background-image: repeating-linear-gradient(
    -45deg,
    rgb(247 245 240 / 5%) 0 1px,
    transparent 1px 9px
  );
}

.card__media--icon svg {
  inline-size: 3.25rem;
  block-size: 3.25rem;
  color: var(--safety-300);
  position: relative;
  z-index: 1;
}


/* ---------- Job sequence ---------- */

/* Replaces the before/after comparison slider. The company's photos of a single
   job are genuinely before/during/after, but shot from three different positions —
   a wipe-to-compare would misalign the house and read as a trick. Three framed
   stages tell the same story honestly. */
.job {
  display: grid;
  gap: var(--space-l);
  counter-reset: jobstep;
}

@media (min-width: 52rem) {
  .job {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-m);
  }
}

.job__item {
  counter-increment: jobstep;
  position: relative;
}

.job__media {
  position: relative;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--surface-sunk);
}

/* .job__frame exists solely to hang the connector arrow on: it matches the media box
   exactly but does NOT clip, whereas .job__media must clip to keep its rounded
   corners. Anchoring to the frame rather than to .job__item also keeps the arrow
   level with the photo instead of dropping toward the caption. */
.job__frame {
  position: relative;
}

/* The sequence reads left-to-right on wide screens. */
@media (min-width: 52rem) {
  .job__item:not(:last-child) .job__frame::after {
    content: '';
    position: absolute;
    inset-block-start: 50%;
    inset-inline-end: calc(-1 * var(--space-m) / 2 - 9px);
    inline-size: 18px;
    block-size: 18px;
    translate: 0 -50%;
    background: var(--accent);
    clip-path: polygon(0 20%, 55% 20%, 55% 0, 100% 50%, 55% 100%, 55% 80%, 0 80%);
    z-index: 2;
  }
}

.job__label {
  position: absolute;
  inset-block-start: var(--space-s);
  inset-inline-start: var(--space-s);
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.6rem;
  background: rgb(16 28 12 / 82%);
  color: var(--bone-50);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: var(--radius-xs);
  backdrop-filter: blur(4px);
}

.job__label::before {
  content: '0' counter(jobstep);
  color: var(--safety-300);
}

.job__item:last-child .job__label {
  background: var(--safety-500);
  color: var(--bark-950);
}

.job__item:last-child .job__label::before {
  color: var(--bark-950);
}

.job__caption {
  margin-block-start: var(--space-s);
  font-size: var(--step--1);
  color: var(--fg-muted);
  line-height: 1.5;
}

.job__foot {
  margin-block-start: var(--space-xl);
}

/* ---------- Social proof (Facebook) ---------- */

/* This replaces the testimonials block. The company has 0 reviews, so there was
   nothing honest to quote — but 1,200 people do follow the page, and that is real,
   checkable social proof pointing at a channel they actually keep up to date. */
.social {
  display: grid;
  gap: var(--space-2xl);
  align-items: center;
}

@media (min-width: 56rem) {
  .social {
    grid-template-columns: 1fr auto;
    gap: var(--space-3xl);
  }
}

.social__count {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-s);
  margin-block-start: var(--space-l);
  padding: var(--space-s) var(--space-l);
  background: var(--inv-surface);
  border: 1px solid var(--inv-border);
  border-radius: var(--radius-lg);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%);
}

.social__num {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--moss-500);
  font-variant-numeric: tabular-nums;
}

/* ---------- Video ---------- */

/* The presentation video, cut from the company's own Reels.
   preload="none" means the 3.3MB costs nothing until someone presses play — only the
   poster loads. `controls` is on the element itself, so the video still works with JS
   disabled; the custom overlay below is pure enhancement and hides itself under
   .no-js. */
.vid {
  position: relative;
  margin: 0;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--inv-border);
  background: var(--bark-950);
  aspect-ratio: 16 / 9;
}

.vid__el {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
}

.vid__play {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-s);
  inline-size: 100%;
  color: var(--bone-50);
  /* A wash rather than a solid: the poster frame still sells the work underneath. */
  background: linear-gradient(to top, rgb(16 28 12 / 72%), rgb(16 28 12 / 28%));
  transition: background-color var(--dur) var(--ease-out);
}

.no-js .vid__play {
  display: none;
}

.vid.is-playing .vid__play {
  display: none;
}

.vid__play:hover .vid__icon {
  transform: scale(1.08);
  background: var(--safety-500);
}

.vid__icon {
  inline-size: 4.5rem;
  block-size: 4.5rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--safety-500);
  color: var(--bark-950);
  box-shadow: 0 8px 28px rgb(16 28 12 / 45%);
  transition:
    transform var(--dur) var(--ease-out),
    background-color var(--dur) var(--ease-out);
}

.vid__icon svg {
  inline-size: 1.9rem;
  block-size: 1.9rem;
  /* Nudge the triangle so it reads as centred in the circle. */
  margin-inline-start: 4px;
}

.vid__label {
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 600;
  text-shadow: 0 1px 6px rgb(16 28 12 / 60%);
}

.vid__meta {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--bone-200);
  opacity: 0.85;
}

.vid__caption {
  margin-block-start: var(--space-s);
  font-size: var(--step--2);
  color: var(--inv-fg-muted);
  font-family: var(--font-mono);
}

@media (prefers-reduced-motion: reduce) {
  .vid__play:hover .vid__icon {
    transform: none;
  }
}

.social__label {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--inv-fg-muted);
}

.social__note {
  display: flex;
  gap: var(--space-xs);
  margin-block-start: var(--space-l);
  font-size: var(--step--2);
  color: var(--inv-fg-muted);
  line-height: 1.5;
}

.social__note svg {
  inline-size: 1rem;
  block-size: 1rem;
  flex: none;
  margin-block-start: 0.15em;
  color: var(--safety-300);
}

/* ---------- Before / after slider (unused — kept for a future real pair) ---------- */

.ba {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-sunk);
  /* Stops the browser from panning the page while dragging the handle. */
  touch-action: pan-y;
  cursor: ew-resize;
  user-select: none;
  border: 1px solid var(--border);
}

/* The "before" image is a .media--fill picture (blur-up). The "after" is a bare
   <img> stacked over it — later in the DOM, so it wins without a z-index. */
.ba__img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  pointer-events: none;
}

/* The "after" layer is clipped to the handle position. clip-path animates on the
   compositor and avoids reflowing the image. */
.ba__after {
  clip-path: inset(0 0 0 var(--pos, 50%));
}

.ba__label {
  position: absolute;
  inset-block-start: var(--space-m);
  padding: 0.35rem 0.7rem;
  background: rgb(16 28 12 / 80%);
  color: var(--bone-50);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border-radius: var(--radius-xs);
  pointer-events: none;
  backdrop-filter: blur(4px);
}

.ba__label--before {
  inset-inline-start: var(--space-m);
}

.ba__label--after {
  inset-inline-end: var(--space-m);
  background: var(--safety-500);
  color: var(--bark-950);
}

.ba__handle {
  position: absolute;
  inset-block: 0;
  inset-inline-start: var(--pos, 50%);
  inline-size: 3px;
  background: var(--bone-50);
  transform: translateX(-50%);
  pointer-events: none;
  box-shadow: 0 0 0 1px rgb(16 28 12 / 25%);
}

.ba__grip {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  translate: -50% -50%;
  inline-size: 3rem;
  block-size: 3rem; /* 48px touch target */
  display: grid;
  place-items: center;
  background: var(--bone-50);
  color: var(--bark-950);
  border-radius: 50%;
  box-shadow: var(--shadow-md);
  transition: transform var(--dur-fast) var(--ease-out);
}

.ba:active .ba__grip {
  transform: scale(1.1);
}

.ba__grip svg {
  inline-size: 1.25rem;
  block-size: 1.25rem;
}

/* The range input is the accessible control: keyboard, screen reader and touch all
   drive it. It's visually transparent but sits over the whole component. */
.ba__range {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
}

.ba__range:focus-visible + .ba__handle .ba__grip {
  outline: 3px solid var(--ring);
  outline-offset: 3px;
}

.ba__caption {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-xs);
  margin-block-start: var(--space-m);
  font-size: var(--step--1);
  color: var(--fg-muted);
}

.ba__caption em {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  opacity: 0.75;
}

/* ---------- Fleet ---------- */

.fleet__grid {
  display: grid;
  gap: var(--space-m);
  grid-template-columns: 1fr;
}

@media (min-width: 48rem) {
  .fleet__grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.fleet__item {
  position: relative;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--inv-border);
}

.fleet__item img {
  transition: transform var(--dur-slow) var(--ease-out);
}

.fleet__item:hover img {
  transform: scale(1.04);
}

/* ---------- Area ---------- */

.area__grid {
  display: grid;
  gap: var(--space-2xl);
}

@media (min-width: 56rem) {
  /* Not 1fr 1fr. The map is a tall, narrow country: given half the width it sits in
     the middle of a mostly empty column. The text column also has more to hold now
     (18 district chips), so it takes the larger share. */
  .area__grid {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    align-items: center;
  }
}

.area__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  list-style: none;
  padding: 0;
}

.area__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 0.9rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 100px;
  font-size: var(--step--1);
  font-weight: 500;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.area__chip:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}

.area__chip::before {
  content: '';
  inline-size: 5px;
  block-size: 5px;
  border-radius: 50%;
  background: var(--moss-500);
}

.area__chip--primary {
  background: var(--primary);
  color: var(--on-primary);
  border-color: var(--primary);
  font-weight: 600;
}

.area__chip--primary::before {
  background: var(--safety-300);
}

.area__note {
  margin-block-start: var(--space-l);
  font-size: var(--step--1);
  color: var(--fg-muted);
}

/* Stylised map — an SVG of the district, not an embedded third-party map (no
   cookies, no external requests, and it renders instantly). */
/* Portugal is roughly 1:2, so this is driven by HEIGHT and lets the width follow.
   The previous district map was near-square and could take inline-size:100%; doing
   that here made the SVG 560x1130 and blew the section out to 1360px tall. */
.area__map {
  display: block;
  block-size: clamp(21rem, 46vw, 34rem);
  inline-size: auto;
  max-inline-size: 100%;
  margin-inline: auto;
  overflow: visible;
}

/* --border-strong left the outline at 1.41:1 on the section background — the country
   was barely a shape. --primary is a brand green that flips per mode (forest-700 on
   light, moss-500 on dark) and lands above 7:1 either way. */
.area__map .region {
  fill: var(--surface);
  stroke: var(--primary);
  stroke-width: 1.5;
  transition: fill var(--dur) var(--ease-out);
}

.area__map .region--active {
  fill: color-mix(in srgb, var(--moss-500) 22%, var(--surface));
}

/* --accent-text, not --safety-500. The pins carry meaning (they mark where the company
   works), so WCAG 1.4.11 wants 3:1 against the shape behind them. Flat safety-500
   managed only 2.75:1 on the dark-mode country fill. --accent-text is the accent that
   already flips per mode — darker orange on light, safety-300 on dark — and clears it
   on both. */
.area__map .pin {
  fill: var(--accent-text);
}

.area__map .pin-ring {
  fill: none;
  stroke: var(--accent-text);
  stroke-width: 2;
  transform-origin: center;
  transform-box: fill-box;
  animation: ping 2.6s var(--ease-out) infinite;
}

@keyframes ping {
  0% {
    transform: scale(0.6);
    opacity: 0.9;
  }
  70%,
  100% {
    transform: scale(2.4);
    opacity: 0;
  }
}

.area__map text {
  font-family: var(--font-mono);
  font-size: 11px;
  fill: var(--fg-muted);
}

.area__map .label--primary {
  fill: var(--fg);
  font-weight: 500;
}

/* ---------- Testimonials ---------- */

.quotes {
  display: grid;
  gap: var(--space-l);
}

@media (min-width: 56rem) {
  .quotes {
    grid-template-columns: repeat(3, 1fr);
  }
}

.quote {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  padding: var(--space-l);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%);
}

.quote__mark {
  inline-size: 1.75rem;
  block-size: 1.75rem;
  color: var(--accent);
  flex: none;
}

.quote__text {
  flex: 1;
  font-size: var(--step-0);
  line-height: 1.6;
}

.quote__author {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  padding-block-start: var(--space-m);
  border-block-start: 1px solid var(--border);
}

.quote__avatar {
  inline-size: 2.5rem;
  block-size: 2.5rem;
  display: grid;
  place-items: center;
  background: var(--primary);
  color: var(--on-primary);
  border-radius: 50%;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step--1);
  flex: none;
}

.quote__name {
  font-weight: 600;
  font-size: var(--step--1);
}

.quote__role {
  font-size: var(--step--2);
  color: var(--fg-muted);
}

/* ---------- FAQ ---------- */

.faq__grid {
  display: grid;
  gap: var(--space-2xl);
}

@media (min-width: 62rem) {
  .faq__grid {
    grid-template-columns: 22rem 1fr;
    gap: var(--space-3xl);
  }

  .faq__aside {
    position: sticky;
    inset-block-start: 6.5rem;
    align-self: start;
  }
}

.faq__list {
  border-block-start: 1px solid var(--border);
}

.faq__item {
  border-block-end: 1px solid var(--border);
}

.faq__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-m);
  inline-size: 100%;
  padding: var(--space-l) 0;
  text-align: start;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.3;
  color: var(--fg);
  transition: color var(--dur-fast) var(--ease-out);
}

.faq__q:hover {
  color: var(--accent-text);
}

.faq__icon {
  inline-size: 1.5rem;
  block-size: 1.5rem;
  flex: none;
  margin-block-start: 0.15em;
  color: var(--accent-text);
  transition: transform var(--dur) var(--ease-out);
}

.faq__q[aria-expanded='true'] .faq__icon {
  transform: rotate(45deg);
}

/* Animating to a fixed max-height guesses wrong and either clips long answers or
   leaves dead space. grid-template-rows 0fr -> 1fr animates to the content's real
   height, and is supported everywhere we target. */
.faq__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur) var(--ease-out);
}

.faq__item.is-open .faq__a {
  grid-template-rows: 1fr;
}

.faq__a-inner {
  overflow: hidden;
}

.faq__a p {
  padding-block-end: var(--space-l);
  color: var(--fg-muted);
  max-width: var(--measure);
  line-height: 1.6;
}

.faq__disclaimer {
  display: flex;
  gap: var(--space-s);
  margin-block-start: var(--space-xl);
  padding: var(--space-m);
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: var(--step--2);
  color: var(--fg-muted);
  line-height: 1.55;
}

.faq__disclaimer svg {
  inline-size: 1.1rem;
  block-size: 1.1rem;
  flex: none;
  margin-block-start: 0.1em;
}

/* ---------- CTA band ---------- */

.band {
  position: relative;
  overflow: clip;
  background: var(--bark-950);
  color: var(--inv-fg);
  isolation: isolate;
}

.band__media {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.band__img {
  filter: saturate(0.6);
}

.band__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to right,
    rgb(16 28 12 / 95%) 0%,
    rgb(16 28 12 / 85%) 45%,
    rgb(16 28 12 / 65%) 100%
  );
}

.band__inner {
  position: relative;
  padding-block: clamp(3.5rem, 8vw, 6rem);
  max-width: 44rem;
}

.band__title {
  font-size: var(--step-4);
  margin-block: var(--space-m) var(--space-m);
}

.band__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin-block-start: var(--space-xl);
}

/* ---------- Form ---------- */

.quote-form {
  display: grid;
  gap: var(--space-2xl);
}

@media (min-width: 62rem) {
  .quote-form {
    grid-template-columns: 1fr 1.15fr;
    gap: var(--space-3xl);
  }
}

.form {
  display: grid;
  gap: var(--space-m);
  padding: var(--space-l);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

@media (min-width: 40rem) {
  .form {
    padding: var(--space-xl);
  }
}

.form__row {
  display: grid;
  gap: var(--space-m);
}

@media (min-width: 34rem) {
  .form__row--2 {
    grid-template-columns: 1fr 1fr;
  }
}

.field {
  display: grid;
  gap: 0.35rem;
}

.field__label {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-size: var(--step--1);
  font-weight: 600;
}

.field__opt {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 400;
  color: var(--fg-muted);
}

.field__req {
  color: var(--danger);
}

.field__help {
  font-size: var(--step--2);
  color: var(--fg-muted);
}

.input,
.select,
.textarea {
  inline-size: 100%;
  min-block-size: 3rem; /* >= 44px touch target */
  padding: 0.7rem 0.85rem;
  background: var(--bg);
  color: var(--fg);
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius);
  font-size: 1rem; /* 16px min or iOS zooms on focus */
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}

.input:hover,
.select:hover,
.textarea:hover {
  border-color: var(--fg-muted);
}

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--ring);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 25%, transparent);
}

.textarea {
  min-block-size: 7rem;
  resize: vertical;
  line-height: 1.5;
}

.select {
  appearance: none;
  /* Chevron drawn as an inline SVG data URI so it needs no extra request and
     inherits nothing that could break in dark mode. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2355635a' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 1.1rem;
  padding-inline-end: 2.5rem;
}

.field.is-invalid .input,
.field.is-invalid .select,
.field.is-invalid .textarea {
  border-color: var(--danger);
}

.field__error {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--step--2);
  font-weight: 500;
  color: var(--danger);
}

.field__error svg {
  inline-size: 0.9rem;
  block-size: 0.9rem;
  flex: none;
}

.field__error:empty {
  display: none;
}

.check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-s);
  cursor: pointer;
}

/* 24px square meets WCAG 2.2 target size on the input itself; the wrapping <label>
   makes the whole row tappable, so the effective target is larger again. */
.check input {
  inline-size: 1.5rem;
  block-size: 1.5rem;
  margin: 0;
  flex: none;
  accent-color: var(--forest-700);
  cursor: pointer;
}

.check span {
  font-size: var(--step--1);
  line-height: 1.45;
}

.form__privacy {
  display: flex;
  gap: var(--space-xs);
  font-size: var(--step--2);
  color: var(--fg-muted);
  line-height: 1.5;
}

.form__privacy svg {
  inline-size: 1rem;
  block-size: 1rem;
  flex: none;
  margin-block-start: 0.1em;
  color: var(--moss-500);
}

.form__summary {
  padding: var(--space-m);
  background: color-mix(in srgb, var(--danger) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
  border-radius: var(--radius);
  color: var(--danger);
  font-size: var(--step--1);
}

.form__summary[hidden] {
  display: none;
}

.form__summary ul {
  margin-block-start: var(--space-xs);
  padding-inline-start: var(--space-m);
}

.form__summary a {
  color: inherit;
}

/* Success panel replaces the form in place, so focus can move to it. */
.form__done {
  display: grid;
  gap: var(--space-s);
  place-items: center;
  text-align: center;
  padding: var(--space-2xl) var(--space-l);
}

.form__done svg {
  inline-size: 3rem;
  block-size: 3rem;
  color: var(--moss-500);
}

.form__done h3 {
  font-size: var(--step-2);
}

.form__done p {
  color: var(--fg-muted);
  font-size: var(--step--1);
}

/* ---------- Contact details ---------- */

.contact__list {
  display: grid;
  gap: var(--space-m);
  list-style: none;
  padding: 0;
  margin-block-start: var(--space-xl);
}

.contact__item {
  display: flex;
  gap: var(--space-m);
  align-items: flex-start;
  padding-block-end: var(--space-m);
  border-block-end: 1px solid var(--border);
}

.contact__icon {
  inline-size: 2.5rem;
  block-size: 2.5rem;
  display: grid;
  place-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--accent-text);
  flex: none;
}

.contact__icon svg {
  inline-size: 1.15rem;
  block-size: 1.15rem;
}

.contact__label {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.contact__value {
  font-size: var(--step-1);
  font-weight: 600;
  text-decoration: none;
  letter-spacing: -0.01em;
}

/* These are the phone/WhatsApp/email links — the ones a visitor on a phone is most
   likely to actually tap. Give them a real target rather than the text's own height. */
a.contact__value {
  display: inline-block;
  padding-block: 0.35rem;
}

a.contact__value:hover {
  color: var(--accent-text);
}

.contact__value--sm {
  font-size: var(--step-0);
  font-weight: 400;
}

/* ---------- Footer ---------- */

.footer {
  background: var(--inv-bg);
  color: var(--inv-fg);
  padding-block: var(--space-3xl) var(--space-xl);
  /* Clear the sticky mobile action bar. */
  padding-block-end: calc(var(--space-xl) + var(--bar-h, 0px));
}

.footer__grid {
  display: grid;
  gap: var(--space-2xl);
  padding-block-end: var(--space-2xl);
  border-block-end: 1px solid var(--inv-border);
}

@media (min-width: 48rem) {
  .footer__grid {
    grid-template-columns: 1.5fr 1fr 1fr;
  }
}

@media (min-width: 68rem) {
  .footer__grid {
    grid-template-columns: 2fr 1fr 1fr 1.2fr;
  }
}

.footer__about {
  color: var(--inv-fg-muted);
  font-size: var(--step--1);
  max-width: 34ch;
  margin-block-start: var(--space-m);
}

.footer__title {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--safety-300);
  margin-block-end: var(--space-m);
}

.footer__list {
  display: grid;
  gap: var(--space-2xs);
  list-style: none;
  padding: 0;
  font-size: var(--step--1);
}

/* These are stacked navigation links, not links inline in prose, so WCAG 2.2's
   24px target minimum applies. Padding rather than gap, so the tap area itself
   grows instead of just the space between. */
.footer__list a {
  display: inline-block;
  padding-block: 0.3rem;
  color: var(--inv-fg-muted);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}

.footer__list a:hover {
  color: var(--inv-fg);
  text-decoration: underline;
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  padding-block-start: var(--space-xl);
  font-size: var(--step--2);
  color: var(--inv-fg-muted);
}

.footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-m);
  list-style: none;
  padding: 0;
}

.footer__legal a {
  display: inline-block;
  padding-block: 0.3rem;
  color: inherit;
}

/* ---------- Sticky mobile action bar ---------- */

/* Phone-first CTA. Hidden on desktop where the header CTA is always visible. */
.bar {
  position: fixed;
  inset-block-end: 0;
  inset-inline: 0;
  z-index: var(--z-sticky);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border);
  border-block-start: 1px solid var(--border);
  padding-block-end: env(safe-area-inset-bottom);
  transform: translateY(110%);
  transition: transform var(--dur) var(--ease-out);
}

.bar.is-visible {
  transform: translateY(0);
}

.bar__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  min-block-size: 3.5rem;
  padding: var(--space-xs);
  background: var(--surface);
  color: var(--fg);
  font-size: var(--step--2);
  font-weight: 600;
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.bar__item:active {
  background: var(--surface-sunk);
}

.bar__item svg {
  inline-size: 1.15rem;
  block-size: 1.15rem;
}

.bar__item--accent {
  background: var(--safety-500);
  color: var(--bark-950);
}

.bar__item--accent:active {
  background: var(--safety-600);
}

@media (min-width: 62rem) {
  .bar {
    display: none;
  }
}

/* ---------- Blur-up images ---------- */

/* The LQIP is a 16px base64 webp inlined on the wrapper. The real image fades in
   over it once decoded.

   .media--fill absolutely fills its parent, so the PARENT is responsible for
   reserving the box (via aspect-ratio or its own positioning). That's what keeps
   CLS at 0. Note this rule must stay after any component rule it overrides —
   `.media` and `.hero__media` have equal specificity, so source order decides. */
.media {
  position: relative;
  overflow: hidden;
  background-size: cover;
  background-position: center;
}

.media--fill {
  position: absolute;
  inset: 0;
}

/* <picture> is display:block but height:auto, so an img sized at block-size:100%
   would resolve against auto and collapse back to its intrinsic ratio. Sizing the
   picture explicitly is what makes object-fit: cover actually crop to the box. */
.media > picture {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.media img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.media::after {
  content: '';
  position: absolute;
  inset: 0;
  backdrop-filter: blur(12px);
  transition: opacity var(--dur-slow) var(--ease-out);
  pointer-events: none;
}

.media.is-loaded::after {
  opacity: 0;
}

.media img {
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-out);
}

.media.is-loaded img {
  opacity: 1;
}

/* ---------- Scroll reveal ---------- */

/* Elements start displaced and are released by IntersectionObserver adding
   .is-in. If JS never runs, .reveal has no effect at all — the no-js rule below
   guarantees content is visible. Only transform/opacity animate. */
.reveal {
  opacity: 0;
  transform: translateY(1.25rem);
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  transition-delay: var(--delay, 0ms);
  will-change: transform, opacity;
}

.reveal.is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Two independent guarantees that content is never trapped behind an animation:
   .no-js      — JS disabled entirely, the inline head script never ran
   .reveal-all — JS enabled but main.js failed to boot within the failsafe window */
.no-js .reveal,
.reveal-all .reveal {
  opacity: 1;
  transform: none;
}

/* ---------- Reduced motion ---------- */

/* Honour the OS setting: kill decorative motion outright, keep state changes
   instant rather than animated. Content must never depend on an animation to
   become visible. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }

  .menu.is-open .menu__link {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .card:hover {
    transform: none;
  }

  .card:hover .card__img,
  .fleet__item:hover img {
    transform: none;
  }
}

/* ---------- Print ---------- */

/* Owners print this page to take to the Câmara or to compare quotes. Make it
   legible on paper: drop the furniture, expose link targets. */
@media print {
  .header,
  .bar,
  .menu,
  .hero__media,
  .band__media,
  .skip-link,
  .ba__grip,
  .form,
  .fleet {
    display: none !important;
  }

  body {
    background: #fff;
    color: #000;
    font-size: 11pt;
  }

  .hero,
  .section--dark,
  .band,
  .footer {
    background: #fff !important;
    color: #000 !important;
  }

  .hero {
    min-block-size: auto;
    padding-block: 1rem;
  }

  .section {
    padding-block: 1rem;
    break-inside: avoid;
  }

  .faq__item.is-open .faq__a,
  .faq__a {
    grid-template-rows: 1fr;
  }

  a[href^='http']::after {
    content: ' (' attr(href) ')';
    font-size: 9pt;
    word-break: break-all;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }
}

/* ---------- Contact Showcase ---------- */

.contact-showcase {
  background: var(--inv-bg);
  color: var(--inv-fg);
}

.contact-showcase__content > * + * {
  margin-block-start: var(--space-l);
}

.contact-showcase__title {
  font-size: var(--step-4);
}

.contact-showcase__lead {
  font-size: var(--step-1);
  color: var(--inv-fg-muted);
  max-width: var(--measure);
}

.contact-showcase__methods {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

.contact-method {
  display: flex;
  gap: var(--space-l);
  padding: var(--space-l);
  background: var(--inv-surface);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  transition: transform var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}

.contact-method:hover {
  background: var(--bark-800);
  transform: translateY(-2px);
}

.contact-method__icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  background: var(--safety-500);
  color: var(--on-accent);
  border-radius: var(--radius);
  font-size: var(--step-1);
}

.contact-method__content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-xs);
}

.contact-method__label {
  display: block;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--safety-300);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.contact-method__value {
  display: block;
  font-size: var(--step-1);
  font-family: var(--font-mono);
  color: var(--inv-fg);
}
