:root {
  --bg: #020304;
  --bg-elevated: #06080f;
  --bg-card: #090c17;
  --border: rgba(182, 217, 252, 0.10);
  --border-strong: rgba(182, 217, 252, 0.20);
  --glass-bg: rgba(9, 13, 24, 0.6);
  --glass-highlight: rgba(216, 236, 248, 0.08);
  --text-primary: #f4f7ff;
  --text-secondary: #9aa5c4;
  --text-muted: #5c6789;
  --accent: #3b82f6;
  --accent-hover: #60a5fa;
  --accent-soft: rgba(59, 130, 246, 0.14);
  --accent-glow: rgba(59, 130, 246, 0.35);
  --radius-sm: 6px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --section-gap: clamp(72px, 11vw, 128px);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

html {
  height: 100%;
}

body {
  margin: 0;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text-primary);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-weight: 400;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "tnum" 1, "ss01" 1;
  position: relative;
}

main {
  flex: 1 0 auto;
}

.footer {
  flex-shrink: 0;
}

/* Ambient blueprint grid, sits behind all in-flow content */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(rgba(182, 217, 252, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(182, 217, 252, 0.05) 1px, transparent 1px);
  background-size: 88px 88px;
  pointer-events: none;
}

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

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 24px;
}

h1, h2, h3 {
  margin: 0;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

p {
  margin: 0;
}

.eyebrow {
  text-transform: uppercase;
  font-size: 12px;
  letter-spacing: 0.12em;
  color: var(--accent-hover);
  font-weight: 600;
  margin: 0 0 12px;
}

.eyebrow-with-icons {
  display: flex;
  align-items: center;
  gap: 7px;
  /* Without this, a longer eyebrow (e.g. "Google/Meta Ads Results" with
     two icons) can wrap to a second line at some tablet widths while a
     shorter one in another section doesn't, pushing that section's
     heading down and throwing every heading out of alignment with its
     neighbours'. Keeping every eyebrow to one line always keeps that
     vertical rhythm consistent regardless of viewport width. */
  white-space: nowrap;
}

.eyebrow-icons {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
}

.eyebrow-icons img {
  width: 16.8px;
  height: 16.8px;
  object-fit: contain;
  display: block;
}

.eyebrow-star {
  font-size: 16.8px;
  line-height: 1;
  color: var(--accent-hover);
}

.lede {
  color: var(--text-secondary);
  font-size: clamp(16px, 1.5vw, 18px);
  max-width: 640px;
  font-weight: 300;
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 14px 28px;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 500;
  border: 1px solid transparent;
  transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease, border-color 0.2s ease;
  white-space: nowrap;
}

.btn-primary {
  background: var(--accent);
  color: #ffffff;
}

.btn-primary:hover {
  background: var(--accent-hover);
  box-shadow: 0 0 0 4px var(--accent-soft);
  transform: translateY(-1px);
}

.btn-primary {
  position: relative;
  animation: btn-pulse 3.2s ease-in-out infinite;
}

@keyframes btn-pulse {
  0%, 100% {
    box-shadow: 0 0 0 0 var(--accent-glow);
  }
  50% {
    box-shadow: 0 0 0 8px rgba(59, 130, 246, 0);
  }
}

.btn-ghost {
  background: transparent;
  border-color: var(--border-strong);
  color: var(--text-primary);
}

.btn-ghost:hover {
  border-color: var(--accent-hover);
  color: var(--accent-hover);
  transform: translateY(-1px);
}

.btn-small {
  padding: 10px 18px;
  font-size: 14px;
}

/* ---------- Nav ---------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(4, 6, 12, 0.82);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border);
  transition: border-color 0.3s ease, background 0.3s ease;
}

.nav.scrolled {
  border-bottom-color: var(--border-strong);
  background: rgba(4, 6, 12, 0.96);
}

.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 18px;
  padding-bottom: 18px;
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

/* Split from the one logo.png into two separate crops (logo-icon.png,
   logo-text.png) sharing the same vertical crop band, so scaling both to
   the same height here reproduces their original relative alignment —
   just as two independently-coloured mask layers instead of one. */
.logo-icon-mark,
.logo-text-mark {
  display: block;
  height: 44px;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

.logo-icon-mark {
  aspect-ratio: 595 / 616;
  background-color: var(--accent);
  -webkit-mask-image: url("/images/logo-icon.png");
  mask-image: url("/images/logo-icon.png");
}

.logo-text-mark {
  aspect-ratio: 1395 / 616;
  background-color: #ffffff;
  -webkit-mask-image: url("/images/logo-text.png");
  mask-image: url("/images/logo-text.png");
}

.footer .logo-icon-mark,
.footer .logo-text-mark {
  height: 34px;
}

.nav-links {
  display: flex;
  gap: 32px;
}

.nav-links a {
  font-size: 14px;
  color: var(--text-secondary);
  transition: color 0.2s ease;
}

.nav-links a:hover {
  color: var(--text-primary);
}

.nav-links a.active,
.mobile-menu a.active {
  color: var(--text-primary);
}

.nav-links a {
  position: relative;
}

.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -4px;
  width: 100%;
  height: 1px;
  background: var(--accent-hover);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s ease;
}

.nav-links a:hover::after {
  transform: scaleX(1);
}

@media (max-width: 760px) {
  .nav-links {
    display: none;
  }
  .nav-inner > .btn-primary.btn-small {
    display: none;
  }
}

/* Mobile hamburger toggle */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 32px;
  height: 32px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
}

@media (max-width: 760px) {
  .nav-toggle {
    display: flex;
  }
}

.nav-toggle span {
  display: block;
  width: 100%;
  height: 2px;
  background: var(--text-primary);
  border-radius: 2px;
  transition: transform 0.3s ease, opacity 0.2s ease;
}

.nav.menu-open .nav-toggle span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav.menu-open .nav-toggle span:nth-child(2) {
  opacity: 0;
}

.nav.menu-open .nav-toggle span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* Mobile dropdown menu */
.mobile-menu {
  display: none;
  flex-direction: column;
  padding: 4px 24px 24px;
  border-top: 1px solid var(--border);
  background: rgba(4, 6, 12, 0.98);
}

.nav.menu-open .mobile-menu {
  display: flex;
}

.mobile-menu a {
  padding: 14px 0;
  font-size: 15px;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
}

.mobile-menu a:last-child {
  border-bottom: none;
  margin-top: 12px;
  text-align: center;
}

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

.hero {
  position: relative;
  overflow: hidden;
  padding: calc(var(--section-gap) + 24px) 0 var(--section-gap);
}

.hero-blobs {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.halo {
  position: absolute;
  top: -220px;
  left: 50%;
  transform: translateX(-50%);
  width: 900px;
  height: 500px;
  background: radial-gradient(ellipse at center, rgba(182, 217, 252, 0.16), transparent 70%);
  pointer-events: none;
}

.blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(60px);
  opacity: 0.5;
}

.blob-1 {
  width: 480px;
  height: 480px;
  top: -160px;
  left: -80px;
  background: radial-gradient(circle, rgba(59,130,246,0.35), transparent 70%);
  animation: blob-float-1 16s ease-in-out infinite;
}

.blob-2 {
  width: 520px;
  height: 520px;
  top: -100px;
  right: -160px;
  background: radial-gradient(circle, rgba(96,165,250,0.22), transparent 70%);
  animation: blob-float-2 20s ease-in-out infinite;
}

@keyframes blob-float-1 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(40px, 30px) scale(1.1); }
}

@keyframes blob-float-2 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(-30px, 20px) scale(0.95); }
}

.hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 0.9fr 1.25fr;
  gap: 40px;
  align-items: center;
}

.hero-text {
  max-width: 560px;
}

@media (max-width: 960px) {
  .hero-grid {
    grid-template-columns: 1fr;
  }
  .hero-text {
    max-width: 100%;
  }
}

.hero h1 {
  font-size: clamp(38px, 6vw, 68px);
  letter-spacing: -0.03em;
  margin-bottom: 24px;
  background: linear-gradient(180deg, #ffffff 30%, #b6d9fc 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero .lede {
  margin-bottom: 36px;
}

.hero-actions {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

/* --section-gap scales with viewport WIDTH (11vw), which doesn't shrink
   for a narrow-but-tall phone screen the way it needs to — on mobile it
   just sits at its 72px floor top and bottom, plus the hero-visual's own
   padding on top of that. Together that was tall enough to fill the whole
   viewport before any of "Quick Facts" peeked into view. Cut both down
   specifically on mobile so there's always a hint of the next section. */
@media (max-width: 640px) {
  .hero {
    padding: 32px 0 40px;
  }
  .hero-visual {
    /* Break out of .container's 24px side padding so the screenshot can
       run almost edge to edge on phones, instead of being boxed in by
       the same padding every other section uses. */
    width: calc(100% + 48px);
    margin-left: -24px;
    margin-right: -24px;
    padding: 6px;
  }
  .hero .lede {
    margin-bottom: 20px;
  }
}

/* ---------- Section head ---------- */

.section-head {
  max-width: 640px;
  margin-bottom: 56px;
}

.section-head h2 {
  font-size: clamp(28px, 4vw, 40px);
}

/* ---------- Sub-page header ---------- */

.page-header {
  position: relative;
  overflow: hidden;
  padding: calc(var(--section-gap) * 0.7) 0 calc(var(--section-gap) * 0.5);
  text-align: left;
}

.page-header .eyebrow {
  margin-bottom: 16px;
}

.page-header h1 {
  font-size: clamp(34px, 5vw, 52px);
  letter-spacing: -0.03em;
  margin-bottom: 20px;
}

.page-header .lede {
  max-width: 640px;
}

@media (max-width: 640px) {
  .page-header {
    padding: 24px 0 20px;
  }
}

/* Swap in a shorter H1 on mobile only, where the full phrase wraps to two
   lines — the desktop/tablet copy is unaffected. */
.h1-mobile-short {
  display: none;
}

@media (max-width: 640px) {
  .h1-mobile-short {
    display: inline;
  }
  .h1-full {
    display: none;
  }
}

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

.faq {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.faq-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 760px;
}

.faq-item {
  background: var(--glass-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 0 24px;
  transition: border-color 0.25s ease;
}

.faq-item[open] {
  border-color: var(--border-strong);
}

.faq-item summary {
  list-style: none;
  cursor: pointer;
  padding: 20px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-weight: 500;
  color: var(--text-primary);
  font-size: 16px;
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary::after {
  content: "+";
  font-size: 22px;
  font-weight: 300;
  color: var(--accent-hover);
  flex-shrink: 0;
  transition: transform 0.25s ease;
}

.faq-item[open] summary::after {
  transform: rotate(45deg);
}

.faq-item p {
  color: var(--text-secondary);
  font-size: 14px;
  font-weight: 300;
  line-height: 1.6;
  padding-bottom: 20px;
  margin: 0;
}

/* ---------- Page-bottom CTA band ---------- */

.page-cta {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
  text-align: center;
  background: radial-gradient(700px 400px at 50% 0%, var(--accent-soft), transparent 65%);
}

.page-cta-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

.page-cta h2 {
  font-size: clamp(26px, 4vw, 38px);
}

/* ---------- Home: Services teaser ---------- */

.services-teaser-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 40px;
}

.services-teaser-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 24px 16px;
  border-radius: 14px;
}

.services-teaser-card h3 {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary);
}

.section-cta-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--accent-hover);
  font-size: 14px;
  font-weight: 500;
}

@media (max-width: 900px) {
  .services-teaser-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* ---------- Home: About teaser ---------- */

.about-teaser {
  display: flex;
  align-items: center;
  gap: 32px;
  padding: 32px;
  border-radius: 20px;
}

.about-teaser .photo-frame {
  flex-shrink: 0;
}

.about-teaser img {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  /* Default (centred) crop left almost no headroom above his head in this
     circular crop — shift the visible window up a bit for a bit of blue
     buffer above his head. */
  object-position: center 25%;
  border: 1px solid var(--border-strong);
}

/* Small Irish-flag badge on Ciarán's photo (homepage teaser + About page),
   signalling "local" at a glance. */
.photo-frame {
  /* block, not inline-block: on the About page, .about-photo img is
     width:100% of this wrapper, so the wrapper needs to size against its
     column (grid-template-columns: 300px 1fr) rather than shrink-to-fit
     its own content, which is exactly what block gives it here. */
  position: relative;
  display: block;
}

.flag-badge {
  position: absolute;
  bottom: -6px;
  right: -6px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 17px;
  line-height: 1;
  background: var(--bg-card);
  border: 2px solid var(--bg);
  border-radius: 50%;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
}

.about-teaser-title {
  font-size: 21px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  margin-bottom: 8px;
}

.about-teaser-content p {
  color: var(--text-secondary);
  font-size: 15px;
  font-weight: 300;
  margin-bottom: 12px;
  max-width: 560px;
}

@media (max-width: 640px) {
  .about-teaser {
    flex-direction: column;
    text-align: center;
    gap: 20px;
  }
}

/* ---------- Google Reviews ---------- */

.reviews {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.proof-block + .proof-block {
  margin-top: 64px;
}

.about-teaser-section {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.review-summary {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 32px;
  flex-wrap: wrap;
}

.review-summary-score {
  font-size: 40px;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

.review-summary-stars {
  color: #fbbc04;
  font-size: 20px;
  letter-spacing: 2px;
}

.review-summary-count {
  color: var(--text-secondary);
  font-size: 14px;
}

.reviews-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.review-card {
  background: #ffffff;
  border-radius: 14px;
  padding: 22px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);
}

.review-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.review-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--accent);
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 15px;
  flex-shrink: 0;
}

.review-avatar-blue { background: #4285f4; }
.review-avatar-lightblue { background: #29b6f6; }
.review-avatar-orange { background: #e8542a; }
.review-avatar-gray { background: #6b7280; }

.review-meta {
  flex: 1;
  min-width: 0;
}

.review-name {
  font-size: 14px;
  font-weight: 500;
  color: #1a1a1a;
}

.review-date {
  font-size: 12px;
  color: #70757a;
}

.review-stars {
  color: #fbbc04;
  font-size: 15px;
  letter-spacing: 1px;
  margin-bottom: 10px;
}

.review-text {
  font-size: 14px;
  color: #3c4043;
  line-height: 1.5;
}

.review-summary-link-icon {
  width: 18px;
  height: 18px;
  object-fit: contain;
}

/* Closing card in the reviews grid, styled like the "Let's build yours"
   card at the end of the portfolio grid: a big stat, a label, and a link.
   Unlike the other 5 (real Google reviews, styled white to look like the
   actual Google UI), this one drops the white fill for the same dark
   glass look every other section's closing card uses, with matching
   light-on-dark text colours. */
.review-card-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  background: var(--glass-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-strong);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 20px 50px rgba(0, 0, 0, 0.4);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.review-card-cta:hover {
  transform: translateY(-3px);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 26px 60px rgba(59, 130, 246, 0.22), 0 20px 45px rgba(0, 0, 0, 0.5);
}

.review-cta-stat {
  font-size: clamp(28px, 3.6vw, 34px);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  margin-bottom: 18px;
}

.review-cta-stars {
  color: #fbbc04;
  font-size: 0.6em;
  letter-spacing: 1px;
  vertical-align: middle;
}

/* Looks like its own button (border, padding, pill shape) even though the
   whole card is the actual link, so it still reads as "click here". */
.review-cta-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 18px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary);
  transition: border-color 0.2s ease, background 0.2s ease;
}

.review-card-cta:hover .review-cta-link {
  border-color: var(--accent-hover);
  background: var(--accent-soft);
}

@media (max-width: 900px) {
  .reviews-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .reviews-grid {
    grid-template-columns: 1fr;
  }

  /* Keep the mobile list of reviews short: David Murphy, FR Services, and
     Michael R only, plus the closing CTA card. */
  .review-card-hide-mobile {
    display: none;
  }

  /* Keep the review cards from stretching edge to edge on mobile
     (homepage preview and the Work page's full reviews grid). */
  .reviews-grid-narrow {
    max-width: 85%;
    margin-left: auto;
    margin-right: auto;
  }
}

/* ---------- Results ---------- */

.results {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.quick-facts {
  padding: calc(var(--section-gap) * 0.55) 0;
  border-top: 1px solid var(--border);
}

.quick-facts .section-head {
  margin-bottom: 28px;
}

.facts-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}

.fact-card {
  padding: 22px 20px;
  text-align: center;
  border-radius: 14px;
}

.fact-value {
  font-size: clamp(22px, 2.6vw, 28px);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--accent-hover);
  font-variant-numeric: tabular-nums;
  margin-bottom: 6px;
}

.fact-label {
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 300;
  line-height: 1.45;
}

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

@media (max-width: 900px) {
  .facts-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .facts-grid > .fact-card:last-child:nth-child(2n+1) {
    grid-column: 1 / -1;
  }
}

@media (max-width: 600px) {
  .facts-grid {
    grid-template-columns: 1fr;
  }
}

/* ---------- GBP Call Growth ---------- */

.gbp-growth {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.gbp-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
  margin-bottom: 32px;
}

/* If there's an odd one out (e.g. 3 cards), let it stretch full-width */
.gbp-grid > .gbp-card:last-child:nth-child(2n+1) {
  grid-column: 1 / -1;
}

.gbp-grid:not(.ads-results-grid) > .reveal:nth-child(2) {
  transition-delay: 150ms;
}

.ads-results-grid > .reveal {
  transition-delay: 0ms;
}

.gbp-card {
  background: var(--glass-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-strong);
  border-radius: 16px;
  padding: 12px;
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 20px 50px rgba(0, 0, 0, 0.4);
}

.gbp-card img {
  width: 100%;
  display: block;
  border-radius: 10px;
}

/* Ads Results screenshots are all uniform squares, so those cards are
   already the same height and swipe purely sideways. The Google Profile
   Results screenshots aren't (different chart crops), so without this,
   the card height jumps vertically mid-swipe between them, which reads as
   "less smooth" than Ads Results even though the scroll code is identical.
   object-fit: contain (not cover) so nothing in the screenshots gets
   cropped off — any mismatch just letterboxes within the glass card. */
.gbp-grid:not(.ads-results-grid) .gbp-card img {
  aspect-ratio: 1704 / 923;
  object-fit: contain;
}

/* This one's a squarer collage, not a wide dashboard screenshot — fitting
   it into the ratio above would pillarbox it down to a fraction of the
   card's width. Use its own (taller) ratio instead so it fills the width;
   the card is just taller for this one card. */
.gbp-grid:not(.ads-results-grid) .gbp-card img.gbp-collage-img {
  aspect-ratio: 1536 / 1024;
}

.gbp-card-cta {
  aspect-ratio: 1736 / 906;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  cursor: pointer;
  transition: box-shadow 0.3s ease, transform 0.3s ease;
}

.gbp-card-cta:hover {
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 26px 60px rgba(59, 130, 246, 0.22), 0 20px 45px rgba(0, 0, 0, 0.5);
  transform: translateY(-2px);
}

.gbp-cta-content {
  padding: 24px;
}

.gbp-cta-headline {
  font-size: clamp(19px, 2.4vw, 23px);
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  max-width: 280px;
  margin: 0 auto 12px;
}

.gbp-cta-label {
  color: var(--text-secondary);
  font-size: 15px;
  font-weight: 300;
  max-width: 260px;
  margin: 0 auto 18px;
}

@media (max-width: 800px) {
  .gbp-grid {
    grid-template-columns: 1fr;
  }
}

/* Shared swipeable carousel behaviour, used by the ad results, Google
   Profile Results, and Websites We've Built card grids on touch/narrow
   screens: snap-scroll with the centred card magnified and neighbours
   scaled down + blurred. Targets ">" (any direct child) rather than a
   specific card class so it works regardless of card type. */
@media (hover: none), (max-width: 800px) {
  .card-carousel {
    /* !important: this class is meant to override whatever base
       display:grid a specific card-grid class declares, regardless of
       which one happens to come later in the file (that ordering bit
       Websites We've Built once already). */
    display: flex !important;
    grid-template-columns: none;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    gap: 16px;
    /* Equal top/bottom so the arrows' 50%-of-track centering (see
       .carousel-track below) lines up with the true centre of the cards,
       not skewed by an uneven top/bottom split.
       Side padding: flex-basis percentages resolve against this
       container's own content box, i.e. AFTER this padding is already
       subtracted — so with flex-basis below at 100%, a card's actual
       on-screen width works out to (100% - 2 * this padding). Using a
       smaller flex-basis here as well (as this used to) double-shrinks
       the card and, worse, leaves too little real padding for the
       first/last card to ever scroll to a truly centred snap position —
       that's what was making the last card land off-centre. */
    padding: 32px 14.7% 32px;
    margin-bottom: 16px;
    scrollbar-width: none;
  }

  .card-carousel::-webkit-scrollbar {
    display: none;
  }

  .card-carousel > * {
    flex: 0 0 100%;
    scroll-snap-align: center;
    /* !important: portfolio cards also carry .glow-card, which declares its
       own `transition` (border-color/transform/box-shadow, no filter or
       opacity) further down this file. Same specificity + later in the
       cascade means, without this, .glow-card's transition silently wins
       and portfolio cards lose their filter/opacity easing entirely during
       the carousel scroll — transform eases smoothly but blur/opacity snap
       instantly, which is exactly what read as "slower"/less smooth than
       the Ads Results carousel (plain .gbp-card, no competing rule). */
    transition: transform 0.15s ease-out, filter 0.15s ease-out, opacity 0.15s ease-out !important;
    will-change: transform, filter;
  }
}

@media (max-width: 480px) {
  .card-carousel {
    padding-left: 9.5%;
    padding-right: 9.5%;
  }
}

/* Websites We've Built specifically: bigger screenshots on mobile, filling
   most of the screen width, since they need to be legible rather than
   just previewed. Same flex-basis: 100% math as above — actual card width
   works out to (100% - 2 * this padding). */
@media (hover: none), (max-width: 800px) {
  .portfolio-grid.card-carousel {
    padding-left: 4%;
    padding-right: 4%;
  }

  /* Drop the glass-card frame (padding, border, shadow, blur) around each
     real screenshot — not the closing "Let's build yours" card, which
     still needs it since it's text, not a photo. Without the padding
     eating into it, the screenshot fills the whole card width, reading
     larger without changing the carousel's own sizing.
     background stays solid (not none): the two video cards (Castle Tiles,
     C&C Construction) are a different aspect ratio than the fixed photo
     ratio below, so object-fit: contain letterboxes them — with a
     transparent card background that gap exposed whatever was visually
     behind it (the next card over, once the focused card scaled up and
     overlapped), which is what looked like "a card behind it" on scroll.
     A plain fill matching the page background closes that gap invisibly
     without bringing back the old boxed-in card look. */
  .portfolio-grid.card-carousel .portfolio-card:not(.portfolio-card-cta) {
    padding: 0;
    background: var(--bg-card);
    border: none;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

@media (max-width: 480px) {
  .portfolio-grid.card-carousel {
    padding-left: 3%;
    padding-right: 3%;
  }
}

.carousel-wrap {
  position: relative;
}

/* Wraps just the card row + arrows (not the swipe-hint below it), so the
   arrows' 50% vertical centering below is relative to the cards only —
   centering on .carousel-wrap instead (which also contains the swipe-hint
   in normal flow) made the arrows sit above the cards' true centre. */
.carousel-track {
  position: relative;
}

.carousel-arrow {
  display: none;
  align-items: center;
  justify-content: center;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(9, 13, 24, 0.75);
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  z-index: 5;
  cursor: pointer;
  padding: 0;
}

.carousel-arrow-prev {
  left: 2%;
}

.carousel-arrow-next {
  right: 2%;
}

.carousel-arrow.is-disabled {
  opacity: 0.3;
  cursor: not-allowed;
  pointer-events: none;
}

.gbp-card {
  cursor: zoom-in;
}

/* Comes after .gbp-card above so it wins the cascade at equal specificity:
   the CTA card is a link, not a zoomable screenshot. */
.gbp-card-cta {
  cursor: pointer;
}

.lightbox {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  inset: 0;
  z-index: 1000;
  padding: 5vh 5vw;
  background: rgba(6, 8, 15, 0.92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  overflow: auto;
  overscroll-behavior: contain;
  /* Allows pinch-zoom but disables double-tap-to-zoom, which was zooming
     the whole page layout instead of just enlarging the photo. */
  touch-action: manipulation;
  transition: opacity 0.2s ease;
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
}

.lightbox-image {
  max-width: 100%;
  max-height: 90vh;
  margin: auto;
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  cursor: zoom-in;
  transform: scale(0.96);
  transition: transform 0.2s ease;
}

.lightbox.is-open .lightbox-image {
  transform: scale(1);
}

.lightbox-image.is-zoomed {
  max-width: none;
  max-height: none;
  width: 190vw;
  cursor: zoom-out;
  transform: scale(1);
}

@media (min-width: 700px) {
  .lightbox-image.is-zoomed {
    width: auto;
    height: 190vh;
  }
}

.lightbox-close {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 24px;
  right: 24px;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: rgba(9, 13, 24, 0.85);
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  cursor: pointer;
  padding: 0;
}

.swipe-hint {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 4px auto 0;
  width: fit-content;
  padding: 6px 14px;
  border-radius: 999px;
  background: rgba(9, 13, 24, 0.6);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 12px;
  transition: opacity 0.4s ease;
}

.swipe-hint.is-hidden {
  opacity: 0;
  pointer-events: none;
}

.swipe-hint-icon {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--accent-hover);
  animation: swipe-hint-move 1.6s ease-in-out infinite;
}

@keyframes swipe-hint-move {
  0%, 100% {
    transform: translateX(-4px);
  }
  50% {
    transform: translateX(4px);
  }
}

@media (hover: none), (max-width: 800px) {
  .carousel-arrow {
    display: flex;
  }
  .swipe-hint {
    display: flex;
  }
}

/* Desktop/tablet, any carousel: plain grid, a hard guard against any
   leftover mobile-carousel blur/scale inline styles from a viewport resize,
   and the two mobile-only loop clones (marked aria-hidden) hidden entirely
   so the grid shows exactly the real cards, none doubled up. */
@media (hover: hover) and (pointer: fine) and (min-width: 801px) {
  .card-carousel > [aria-hidden="true"] {
    display: none;
  }
  .card-carousel > * {
    filter: none !important;
    transform: none !important;
    opacity: 1 !important;
  }
}

/* Ad results specifically: the whole grid (so every card in it, not just
   the photo inside) 30% smaller on desktop/tablet, centred in the space
   that frees up. */
@media (hover: hover) and (pointer: fine) and (min-width: 801px) {
  .ads-results-grid {
    max-width: 70%;
    margin-left: auto;
    margin-right: auto;
  }
}

/* Ads Results and Google Profile Results CTA card: still spans the full
   row (so it doesn't leave an odd empty grid cell beside it), but on
   desktop/tablet it shrinks down to a slim, low-key strip instead of a
   big feature block the same height as the photo cards next to it — it
   should read as a quiet closing card, not compete with the results. */
@media (hover: hover) and (pointer: fine) and (min-width: 801px) {
  .gbp-card-cta {
    aspect-ratio: auto;
    padding: 16px 24px;
  }

  .gbp-cta-content {
    padding: 0;
  }

  .gbp-cta-headline {
    font-size: 14px;
    max-width: none;
    margin-bottom: 4px;
  }

  .gbp-cta-label {
    font-size: 12px;
    margin-bottom: 6px;
  }

  .gbp-card-cta .portfolio-link {
    font-size: 12px;
  }
}

/* ---------- Services ---------- */

.services {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.service-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

.service-card {
  border-radius: 16px;
  padding: 32px;
}

.service-icon {
  color: var(--accent-hover);
  font-size: 24px;
  margin-bottom: 20px;
}

.service-card h3 {
  font-size: 18px;
  margin-bottom: 10px;
  font-weight: 500;
}

.service-card p {
  color: var(--text-secondary);
  font-size: 15px;
  font-weight: 300;
}

@media (max-width: 900px) {
  .service-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .service-grid {
    grid-template-columns: 1fr;
  }
}

/* ---------- Our Work ---------- */

.work {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.work .container {
  max-width: 1340px;
}

.portfolio-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
}

/* If there's an odd one out, let it stretch full-width as a closing feature card */
.portfolio-grid > .portfolio-card:last-child:nth-child(2n+1) {
  grid-column: 1 / -1;
}

.portfolio-card {
  display: block;
  position: relative;
  padding: 16px;
  border-radius: 16px;
  overflow: hidden;
}

.portfolio-card img,
.portfolio-card video {
  width: 100%;
  /* Matches the site screenshots' native ratio (they're already cropped to
     this), so this is a no-op for those. It only affects the Castle Tiles
     video, which is a different ratio and would otherwise make that one
     card a different height, causing a vertical jump mid-swipe. contain
     (not cover) so nothing gets cropped, just letterboxed if needed. */
  aspect-ratio: 1736 / 906;
  object-fit: contain;
  display: block;
  border-radius: 8px;
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

.portfolio-card:hover img,
.portfolio-card:hover video {
  transform: scale(1.04);
}

.portfolio-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: rgba(5, 7, 13, 0.82);
  opacity: 0;
  transition: opacity 0.3s ease;
  text-align: center;
  padding: 24px;
}

.portfolio-card:hover .portfolio-overlay {
  opacity: 1;
}

.portfolio-card:hover {
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 26px 60px rgba(59, 130, 246, 0.22), 0 20px 45px rgba(0, 0, 0, 0.5);
}

.portfolio-card-cta {
  aspect-ratio: 1736 / 906;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.portfolio-cta-content {
  padding: 24px;
}

.portfolio-cta-stat {
  font-size: clamp(40px, 6vw, 56px);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--accent-hover);
  font-variant-numeric: tabular-nums;
  margin-bottom: 10px;
}

.portfolio-cta-label {
  color: var(--text-secondary);
  font-size: 15px;
  font-weight: 300;
  max-width: 260px;
  margin: 0 auto 18px;
}

.portfolio-overlay span:first-child {
  font-size: 18px;
  font-weight: 500;
  color: var(--text-primary);
}

.portfolio-link {
  font-size: 14px;
  color: var(--accent-hover);
  font-weight: 500;
}

/* Touch devices: no hover to reveal the overlay, so show it always. The
   swipe/carousel mechanics themselves now come from the shared
   .card-carousel rules above. */
@media (hover: none) {
  .portfolio-overlay {
    opacity: 1;
    background: linear-gradient(to top, rgba(5, 7, 13, 0.92) 20%, transparent 70%);
    align-items: flex-start;
    justify-content: flex-end;
    padding: 20px;
  }

  .portfolio-overlay span:first-child {
    font-size: 16px;
  }
}

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

.testimonials {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.testimonial-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.testimonial-card {
  border-radius: 16px;
  padding: 28px;
  margin: 0;
}

.testimonial-card p {
  font-size: 15px;
  color: var(--text-primary);
  font-weight: 300;
  margin-bottom: 20px;
}

.testimonial-card footer {
  color: var(--text-muted);
  font-size: 13px;
}

@media (max-width: 900px) {
  .testimonial-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .testimonial-grid {
    grid-template-columns: 1fr;
  }
}

/* ---------- Client Message ---------- */

.client-message {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.client-message-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

.client-message-frame {
  max-width: 320px;
  width: 100%;
  padding: 10px;
  background: var(--glass-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-strong);
  border-radius: 20px;
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 24px 60px rgba(0, 0, 0, 0.45);
}

.client-message-frame img {
  width: 100%;
  display: block;
  border-radius: 14px;
}

.client-message-caption {
  color: var(--text-secondary);
  font-size: 14px;
  text-align: center;
  max-width: 360px;
}

/* ---------- About ---------- */

.about {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
}

.about-grid {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 56px;
  align-items: start;
}

.about-photo img {
  width: 100%;
  border-radius: 20px;
  border: 1px solid var(--border-strong);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 24px 60px rgba(0, 0, 0, 0.45);
  display: block;
}

.about-photo-caption {
  text-align: center;
  margin-top: 16px;
}

.about-photo-caption strong {
  display: block;
  font-size: 16px;
  font-weight: 500;
  color: var(--text-primary);
}

.about-photo-caption span {
  display: block;
  font-size: 13px;
  color: var(--text-muted);
  margin-top: 2px;
}

.about-content h2 {
  font-size: clamp(26px, 4vw, 36px);
  margin-bottom: 20px;
  max-width: 640px;
}

.about-content .lede {
  margin-bottom: 40px;
  max-width: 100%;
}

.trust-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}

.trust-item {
  background: var(--glass-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 0 0 0 rgba(59, 130, 246, 0);
  border-radius: 16px;
  padding: 24px;
  transition: border-color 0.6s ease, box-shadow 0.6s ease;
}

/* Connector arrows between cards: hidden in the 2-col desktop grid, shown
   as a vertical flow between cards once the grid stacks to one column. */
.trust-arrow {
  display: none;
}

@media (max-width: 760px) {
  .trust-grid {
    display: flex;
    flex-direction: column;
    align-items: stretch;
  }
  .trust-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    padding: 2px 0;
    opacity: 0.7;
    transition: color 0.6s ease, opacity 0.6s ease, filter 0.6s ease;
  }
  .trust-item.in-view + .trust-arrow {
    color: var(--accent-hover);
    opacity: 1;
    filter: drop-shadow(0 0 6px rgba(59, 130, 246, 0.7));
  }
  /* Once a card has lit up, it stays lit as you continue scrolling past it,
     like a trail lighting up behind you. */
  .trust-item.in-view {
    border-color: var(--accent-hover);
    box-shadow: inset 0 1px 0 var(--glass-highlight), 0 0 22px rgba(59, 130, 246, 0.25);
  }
}

.trust-item h3 {
  font-size: 16px;
  font-weight: 500;
  color: var(--accent-hover);
  margin-bottom: 10px;
}

.trust-item p {
  font-size: 14px;
  color: var(--text-secondary);
  font-weight: 300;
}

@media (max-width: 860px) {
  .about-grid {
    grid-template-columns: 1fr;
  }
  .about-photo {
    max-width: 240px;
    margin: 0 auto;
  }
}

@media (max-width: 560px) {
  .trust-grid {
    grid-template-columns: 1fr;
  }
}

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

.cta {
  padding: var(--section-gap) 0;
  border-top: 1px solid var(--border);
  text-align: center;
  background: radial-gradient(700px 400px at 50% 0%, var(--accent-soft), transparent 65%);
}

.cta-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

.cta h2 {
  font-size: clamp(28px, 4vw, 42px);
}

.cta .hero-actions {
  justify-content: center;
  margin-top: 12px;
}

/* ---------- Contact form ---------- */

.contact-form-card {
  width: 100%;
  max-width: 600px;
  margin: 32px auto 0;
  padding: 40px;
  border-radius: 20px;
  background: rgba(20, 27, 46, 0.9);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-strong);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 24px 60px rgba(0, 0, 0, 0.55);
  text-align: left;
}

.contact-form-card h2 {
  font-size: clamp(22px, 3vw, 28px);
  margin-bottom: 24px;
}

@media (max-width: 600px) {
  .contact-form-card {
    padding: 28px 20px;
    margin-top: 16px;
  }
  .contact-form-card h2 {
    margin-bottom: 14px;
  }
  .cta .container {
    padding-left: 44px;
    padding-right: 44px;
  }
  /* .cta's own section-gap top padding, stacked on top of the page-header
     above it, was pushing the form fields well past the fold on mobile —
     the "Contact Us" card wouldn't even start until you'd already
     scrolled. Bottom padding is left alone since that's below the fold
     either way. */
  .cta {
    padding-top: 28px;
  }
}

.contact-form {
  width: 100%;
  max-width: 600px;
  margin: 48px auto 0;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.contact-form-card .contact-form {
  max-width: 100%;
  margin-top: 0;
}

.form-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.form-field label {
  font-size: 13px;
  color: var(--text-secondary);
}

.form-field input,
.form-field textarea {
  background: rgba(9, 13, 24, 0.7);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  padding: 12px 14px;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 15px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.form-field textarea {
  resize: vertical;
  min-height: 120px;
}

.form-field input:focus,
.form-field textarea:focus {
  outline: none;
  border-color: var(--accent-hover);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.contact-form .btn {
  align-self: center;
  border: none;
  cursor: pointer;
}

.contact-form-card .contact-form .btn {
  align-self: center;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.form-field input::placeholder,
.form-field textarea::placeholder {
  color: var(--text-muted);
}

.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
}

.form-error {
  color: #f87171;
  font-size: 14px;
  margin: -8px 0 0;
}

/* ---------- Legal pages (Privacy Policy) ---------- */

.legal-page {
  padding: 0 0 var(--section-gap);
}

.legal-content {
  max-width: 720px;
}

.legal-content h2 {
  font-size: 22px;
  margin-top: 40px;
  margin-bottom: 12px;
}

.legal-content h2:first-child {
  margin-top: 0;
}

.legal-content p {
  color: var(--text-secondary);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.7;
  margin-bottom: 12px;
}

.legal-content a {
  color: var(--accent-hover);
  text-decoration: underline;
}

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

.footer {
  border-top: 1px solid var(--border);
  padding: 48px 0 24px;
}

.footer-top {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 32px;
  padding-bottom: 32px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 20px;
}

.footer-brand {
  max-width: 320px;
}

.footer-tagline {
  color: var(--text-secondary);
  font-size: 14px;
  font-weight: 300;
  line-height: 1.5;
  margin: 14px 0 16px;
}

.footer-whatsapp {
  display: inline-block;
  font-size: 14px;
  font-weight: 500;
  color: var(--accent-hover);
  transition: color 0.2s ease;
}

.footer-whatsapp:hover {
  color: var(--text-primary);
}

.footer-links {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.footer-heading {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: 4px;
}

.footer-links a {
  font-size: 14px;
  color: var(--text-secondary);
  transition: color 0.2s ease;
}

.footer-links a:hover {
  color: var(--text-primary);
}

.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.footer-inner p {
  color: var(--text-muted);
  font-size: 13px;
}

@media (max-width: 700px) {
  .footer-top {
    grid-template-columns: 1fr;
    gap: 28px;
  }
}


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

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

.reveal.in-view {
  opacity: 1;
  transform: translateY(0);
}

/* Staggered entrance for hero children — slower/more spread out than the
   rest of the site's .reveal timing so the hero reads as a deliberate
   sequence (heading, then lede, then button, then visual) rather than
   everything arriving almost at once. */
.hero-text > .reveal,
.hero-visual.reveal {
  transition-duration: 0.9s;
}
.hero-text > .reveal:nth-child(1) { transition-delay: 0ms; }
.hero-text > .reveal:nth-child(2) { transition-delay: 200ms; }
.hero-text > .reveal:nth-child(3) { transition-delay: 400ms; }
.hero-text > .reveal:nth-child(4) { transition-delay: 600ms; }
.hero-visual.reveal { transition-delay: 450ms; }

/* Staggered cascade for grid cards */
.service-grid > .reveal:nth-child(1), .testimonial-grid > .reveal:nth-child(1), .facts-grid > .reveal:nth-child(1), .portfolio-grid > .reveal:nth-child(1), .services-teaser-grid > .reveal:nth-child(1), .reviews-grid > .reveal:nth-child(1) { transition-delay: 0ms; }
.service-grid > .reveal:nth-child(2), .testimonial-grid > .reveal:nth-child(2), .facts-grid > .reveal:nth-child(2), .portfolio-grid > .reveal:nth-child(2), .services-teaser-grid > .reveal:nth-child(2), .reviews-grid > .reveal:nth-child(2) { transition-delay: 90ms; }
.service-grid > .reveal:nth-child(3), .testimonial-grid > .reveal:nth-child(3), .facts-grid > .reveal:nth-child(3), .portfolio-grid > .reveal:nth-child(3), .services-teaser-grid > .reveal:nth-child(3), .reviews-grid > .reveal:nth-child(3) { transition-delay: 180ms; }
.service-grid > .reveal:nth-child(4), .testimonial-grid > .reveal:nth-child(4), .portfolio-grid > .reveal:nth-child(4), .services-teaser-grid > .reveal:nth-child(4), .reviews-grid > .reveal:nth-child(4) { transition-delay: 270ms; }
.service-grid > .reveal:nth-child(5), .testimonial-grid > .reveal:nth-child(5), .portfolio-grid > .reveal:nth-child(5), .reviews-grid > .reveal:nth-child(5) { transition-delay: 360ms; }
.service-grid > .reveal:nth-child(6), .testimonial-grid > .reveal:nth-child(6), .portfolio-grid > .reveal:nth-child(6), .reviews-grid > .reveal:nth-child(6) { transition-delay: 450ms; }
.service-grid > .reveal:nth-child(7) { transition-delay: 540ms; }
.service-grid > .reveal:nth-child(8) { transition-delay: 630ms; }

/* ---------- Hero visual: ranking screenshot + floating badges ---------- */

.hero-visual {
  position: relative;
  padding: 36px;
}

.hero-visual-glow {
  position: absolute;
  inset: -50px;
  z-index: 0;
  background: radial-gradient(circle at 50% 45%, rgba(59, 130, 246, 0.4), rgba(59, 130, 246, 0.14) 45%, transparent 72%);
  filter: blur(30px);
  animation: blob-float-1 16s ease-in-out infinite;
  pointer-events: none;
}

.ranking-img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  display: block;
  border-radius: 16px;
  border: 1px solid var(--border-strong);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 24px 60px rgba(0, 0, 0, 0.45);
}

/* Static row of platform badges under the hero photo. Previously these
   floated around the photo with a continuous bob/rotate + scroll-parallax
   — felt like a distraction. This just fades in once via .reveal like
   everything else on the page, then sits still. */
.hero-badge-row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 24px;
}

.hero-badge-icon {
  width: 40px;
  height: 40px;
  object-fit: contain;
  padding: 8px;
  background: var(--glass-bg);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 8px 20px rgba(0, 0, 0, 0.3);
}

/* A small white chip sized to just the icon glyph, not the whole tile */
.icon-chip {
  background: #ffffff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.icon-chip img {
  width: 86%;
  height: 86%;
  object-fit: contain;
  display: block;
}

.service-icon .icon-chip {
  width: 34px;
  height: 34px;
}

@media (max-width: 640px) {
  .hero-badge-row {
    gap: 10px;
    margin-top: 18px;
  }
  .hero-badge-icon {
    width: 34px;
    height: 34px;
    padding: 6px;
  }
}

/* Cursor-reactive glow + tilt on cards, frosted-glass surface */
.glow-card {
  position: relative;
  background: var(--glass-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 8px 32px rgba(0, 0, 0, 0.35);
  transform: perspective(800px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
  transition: border-color 0.25s ease, transform 0.15s ease-out, box-shadow 0.35s ease;
}

.glow-card:hover {
  border-color: var(--border-strong);
}

.glow-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 50%), rgba(59,130,246,0.16), transparent 65%);
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

.glow-card:hover::before {
  opacity: 1;
}

.service-card:hover .service-icon {
  transform: translateY(-3px) scale(1.1);
}

.service-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 53px;
  height: 53px;
  border-radius: 9999px;
  background: rgba(182, 217, 252, 0.08);
  border: 1px solid var(--border-strong);
  transition: transform 0.25s ease;
  overflow: hidden;
}

.service-icon img {
  width: 29px;
  height: 29px;
  object-fit: contain;
}

/* Two icons combined into one badge, e.g. Facebook + Instagram.
   Both icons are self-contained (their own background baked in), sized and
   inset so every corner stays inside the circular service-icon boundary. */
.service-icon.icon-cluster {
  position: relative;
}

.cluster-icon {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
}

.cluster-icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.cluster-icon-facebook {
  top: 9px;
  left: 9px;
  border-radius: 50%;
  z-index: 1;
}

.cluster-icon-instagram {
  bottom: 9px;
  right: 9px;
  border-radius: 30%;
  overflow: hidden;
  z-index: 2;
}

.cluster-icon-instagram img {
  width: 100%;
  height: 100%;
}

/* Scroll progress bar */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent-hover));
  transform: scaleX(0);
  transform-origin: left;
  z-index: 200;
}

/* Back to top */
.back-to-top {
  position: fixed;
  left: 24px;
  bottom: 24px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  font-size: 18px;
  cursor: pointer;
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease, border-color 0.25s ease, background 0.25s ease;
  z-index: 90;
}

.back-to-top.visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.back-to-top:hover {
  border-color: var(--accent-hover);
  background: var(--accent-soft);
}

/* WhatsApp floating action button */
.whatsapp-fab-wrap {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 56px;
  height: 56px;
  z-index: 90;
}

.whatsapp-fab-wrap::before {
  content: "";
  position: absolute;
  inset: -16px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(190, 255, 217, 0.55), rgba(37, 211, 102, 0.22) 45%, transparent 72%);
  filter: blur(3px);
  z-index: -1;
  animation: wa-glow-pulse 2.6s ease-in-out infinite;
}

.whatsapp-fab {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 32% 28%, #3ee684, #22c55e 60%, #189649 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 24px rgba(37, 211, 102, 0.4);
  transition: box-shadow 0.2s ease;
  animation: wa-wiggle 4s ease-in-out infinite;
}

.whatsapp-fab img {
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.18));
}

.whatsapp-fab:hover {
  box-shadow: 0 10px 30px rgba(37, 211, 102, 0.55);
}

@keyframes wa-glow-pulse {
  0%, 100% {
    transform: scale(0.92);
    opacity: 0.65;
  }
  50% {
    transform: scale(1.08);
    opacity: 1;
  }
}

/* "Someone is typing" bubble. Starts hidden, scaled down into the green
   icon's corner. First pop-out is 15s after the page loads; from then on
   it stays visible for 1 minute, hides for 3 minutes, and keeps
   alternating on that 1-on/3-off clock for as long as the page is open
   (wa-typing-cycle below is one 240s = 60s+180s loop, repeated forever).
   wa-wiggle runs on it too, on the same clock as the icon's own wa-wiggle
   below, so whenever it's visible they jump in sync. Uses the standalone
   scale/translate/rotate properties (rather than `transform`) specifically
   so this animation and wa-wiggle can run at once without one overwriting
   the other's transform. */
.wa-typing {
  position: absolute;
  top: -20px;
  right: -2px;
  display: flex;
  align-items: center;
  gap: 4px;
  background: #ffffff;
  border-radius: 14px;
  padding: 7px 10px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
  transform-origin: bottom right;
  opacity: 0;
  scale: 0.4;
  animation:
    wa-typing-cycle 240s linear 15s infinite backwards,
    wa-wiggle 4s ease-in-out infinite;
}

/* Percentages of the 240s cycle: pop in (~0.45s), hold visible to the
   60s mark (25%), fade out (~0.45s), hold hidden the rest of the way. */
@keyframes wa-typing-cycle {
  0% {
    opacity: 0;
    scale: 0.4;
    animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  0.19% {
    opacity: 1;
    scale: 1;
  }
  25% {
    opacity: 1;
    scale: 1;
    animation-timing-function: ease;
  }
  25.19%, 100% {
    opacity: 0;
    scale: 0.4;
  }
}

.wa-typing::after {
  content: "";
  position: absolute;
  bottom: -4px;
  right: 16px;
  width: 8px;
  height: 8px;
  background: #ffffff;
  clip-path: polygon(0 0, 100% 0, 0 100%);
}

.wa-typing span {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #9aa3ad;
  animation: typing-dot 1.2s infinite ease-in-out;
}

.wa-typing span:nth-child(2) {
  animation-delay: 0.2s;
}

.wa-typing span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes typing-dot {
  0%, 60%, 100% {
    opacity: 0.3;
    transform: translateY(0);
  }
  30% {
    opacity: 1;
    transform: translateY(-2px);
  }
}

@keyframes wa-wiggle {
  0%, 82%, 100% {
    translate: 0 0;
    rotate: 0deg;
  }
  86% {
    translate: 0 -10px;
    rotate: -8deg;
  }
  90% {
    translate: 0 0;
    rotate: 8deg;
  }
  94% {
    translate: 0 -5px;
    rotate: -4deg;
  }
  97% {
    translate: 0 0;
    rotate: 0deg;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0ms !important;
  }
  .btn, .service-card, .glow-card, .service-icon, .back-to-top, .trust-item, .trust-arrow {
    transition: none !important;
  }
  .btn-primary {
    animation: none;
  }
  .blob-1, .blob-2, .hero-visual-glow {
    animation: none;
  }
  .glow-card {
    transform: none !important;
  }
  .whatsapp-fab {
    animation: none !important;
  }
  .wa-typing {
    animation: none !important;
    opacity: 1;
    scale: 1;
  }
  .wa-typing span {
    animation: none !important;
    opacity: 1;
  }
  .swipe-hint-icon {
    animation: none !important;
  }
  .swipe-hint {
    display: none !important;
  }
  .whatsapp-fab-wrap::before {
    animation: none !important;
    opacity: 0.8;
    transform: scale(1);
  }
}
