:root {
  /* ---- typefaces ----
     Geometric display + neutral body. Every font-family in this file points at
     one of these four, so a future typeface swap is a four-line change. */
  --font-display: 'Outfit', 'Segoe UI', system-ui, sans-serif;
  --font-body: 'Plus Jakarta Sans', 'Segoe UI', system-ui, sans-serif;
  --font-label: 'Plus Jakarta Sans', 'Segoe UI', system-ui, sans-serif;
  --font-serif: 'Playfair Display', Georgia, 'Times New Roman', serif;

  /* ---- dark surfaces ----
     Near-black with a red cast rather than the previous brown maroon, so the
     red accent and its glows read as light emitted onto the page. */
  --ink: #0f0709;
  --ink-2: #150a0c;
  --surface: #1c1012;
  --surface-2: #26161a;
  --line: rgba(255, 255, 255, 0.10);

  /* ---- accent ----
     --accent is the fill red: white label text sits on it at 4.83:1. Being
     brighter, --accent-hot is the better TEXT red on near-black (5.97:1 vs
     4.13:1) but a poor fill (white on it is only 3.33:1), so the two are not
     interchangeable in either direction. --accent-hot is also too light for
     the cream sections, which must stay on --accent. */
  --accent: #d92d24;
  --accent-hot: #ff4a3d;
  --accent-deep: #8e1c16;

  /* ---- text ---- */
  --text: #f6efe9;
  --muted: #a8938c;
  --text-on-dark: #f6efe9;
  --muted-on-dark: #a8938c;

  /* ---- cream sections ---- */
  --cream: #f6efe3;
  --ink-on-cream: #1a0c0e;
  --muted-on-cream: #6f5f58;

  /* Review stars: warm amber reads as a rating and clears contrast on the
     dark carousel, where --accent sits at only ~2.6:1. */
  --star: #e8a33d;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  background: var(--ink);
  color: var(--text);
  font-family: var(--font-body);
  min-height: 100vh;
  position: relative;
  overflow-x: hidden;
}

/* signature element: a slow orbit ring echoing the swoosh around the globe in the mark */
.orbit {
  position: fixed;
  top: 50%;
  left: 50%;
  width: min(70vh, 640px);
  height: min(70vh, 640px);
  transform: translate(-50%, -55%);
  border-radius: 50%;
  background:
    conic-gradient(from 0deg, transparent 0deg, var(--accent-hot) 40deg, var(--accent) 130deg, var(--accent-deep) 220deg, transparent 300deg);
  filter: blur(60px);
  opacity: 0.22;
  animation: spin 22s linear infinite;
  pointer-events: none;
  z-index: 0;
}

@keyframes spin {
  to { transform: translate(-50%, -55%) rotate(360deg); }
}

.stage {
  position: relative;
  z-index: 1;
  max-width: 640px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.mark {
  width: 128px;
  height: 128px;
  margin-bottom: 1.75rem;
  filter: drop-shadow(0 8px 40px rgba(217, 45, 36, 0.35));
}

.mark img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.eyebrow {
  font-family: var(--font-label);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1.5rem;
}

.headline {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 6.2vw, 4.25rem);
  line-height: 1.04;
  letter-spacing: -0.035em;
  margin: 0 0 1.25rem;
  color: var(--text);
}

.accent-italic {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 500;
  /* --accent-hot, not --accent: on near-black it reads 5.97:1 against 4.13:1.
     The cream sections override this back to --accent (.statement-text
     .accent-italic below), where the hot red drops to 2.92:1. */
  color: var(--accent-hot);
}

.subhead {
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--muted);
  margin: 0 0 2.25rem;
  max-width: 480px;
}

.subhead strong {
  color: var(--text);
  font-weight: 600;
}

.markets {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 0;
  padding: 0;
  margin: 0 0 2.75rem;
  font-family: var(--font-label);
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--text);
}

.markets li { padding: 0 0.85rem; position: relative; }

.markets li + li::before {
  content: '·';
  position: absolute;
  left: -0.1rem;
  color: var(--accent-hot);
}

.cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  color: #fff;
  background: var(--accent);
  padding: 0.875rem 1.75rem;
  border-radius: 999px;
  text-decoration: none;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  box-shadow: 0 8px 30px rgba(217, 45, 36, 0.25);
}

.cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 36px rgba(217, 45, 36, 0.4);
}

.cta:focus-visible,
a:focus-visible {
  outline: 2px solid var(--accent-hot);
  outline-offset: 3px;
}

.foot {
  position: relative;
  z-index: 1;
  margin-top: 3.5rem;
  font-size: 0.8125rem;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.foot .dot { color: var(--accent-hot); }

@media (prefers-reduced-motion: reduce) {
  .orbit { animation: none; }
  .cta { transition: none; }
}

/* ============ layout primitives ============ */
.container {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 1.5rem;
}

.section {
  position: relative;
  z-index: 1;
  padding: 5rem 0;
}

.section-alt {
  background: var(--cream);
  color: var(--ink-on-cream);
  --text: var(--ink-on-cream);
  --muted: var(--muted-on-cream);
}

.section-alt .card,
.section-alt .pricing-card {
  background: rgba(15, 7, 9, 0.04);
  border-color: rgba(15, 7, 9, 0.12);
}

.section-alt .card:hover {
  border-color: rgba(217, 45, 36, 0.5);
}

.section-alt .pricing-card--featured {
  background: rgba(217, 45, 36, 0.08);
  border-color: rgba(217, 45, 36, 0.5);
}

.section-alt .browser-frame-bar {
  background: rgba(15, 7, 9, 0.06);
}

.section-alt .browser-frame-bar span {
  background: rgba(15, 7, 9, 0.2);
}

/* A section eyebrow introduces a centred .section-title, so it centres too.
   Hero eyebrows live inside .hero-content and keep their own alignment. */
.section .container > .eyebrow {
  text-align: center;
  margin-bottom: 0.9rem;
}

.section-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 2.5rem;
  text-align: center;
}

/* ============ header / nav ============ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: transparent;
  /* Not transitioned: the solid state is what keeps the nav legible over the
     cream sections, so it snaps rather than fading in. */
}

/* Solid once the page scrolls past the hero's top, so nav stays legible
   over the cream sections further down. Toggled from script.js.
   The hairline is a box-shadow rather than a border so the header's height
   stays exactly 80px — the Home hero's negative margin depends on it. */
.site-header.scrolled,
.site-header:has(.main-nav.open) {
  background: rgba(15, 7, 9, 0.85);
  backdrop-filter: blur(10px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06);
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 1rem, not 1.5rem: at 1440px the 50px social buttons overflowed the bar by
     14px at the old spacing. Measured, not guessed. */
  gap: 1rem;
  padding: 0 1.5rem;
  /* Fixed height (not min-height, which box-sizing makes non-binding here)
     so the header is exactly 80px at every width — the Home hero pulls
     itself up by that much to sit behind the nav. */
  height: 80px;
}

.logo { display: flex; align-items: center; text-decoration: none; }
.logo-img { height: 40px; width: auto; display: block; }

.main-nav {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  font-family: var(--font-label);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  background: rgba(15, 7, 9, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  padding: 0.9rem 1.75rem;
  backdrop-filter: blur(8px);
}

.main-nav a {
  color: var(--muted);
  text-decoration: none;
  transition: color 0.2s ease;
}

.main-nav a:hover,
.main-nav a.active {
  color: var(--text);
}

.social-icons {
  display: flex;
  align-items: center;
  gap: 0.7rem;
}

.social-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 50px;
  flex-shrink: 0;
  border-radius: 50%;
  /* Two layers: a top-to-bottom sheen over a dark translucent fill. The sheen
     is what makes the ring read as a lit edge catching light rather than a
     flat 1px stroke. */
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.02)),
    rgba(15, 7, 9, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.36);
  backdrop-filter: blur(10px);
  color: var(--text);
  transition: border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
}

.social-icon:hover,
.social-icon:focus-visible {
  border-color: var(--accent-hot);
  box-shadow:
    0 0 0 1px rgba(255, 74, 61, 0.35),
    0 8px 28px -6px rgba(255, 74, 61, 0.55);
  transform: translateY(-2px);
}

.social-icon svg {
  width: 21px;
  height: 21px;
}

.header-cta {
  font-size: 0.8125rem;
  padding: 0.75rem 1.5rem;
  white-space: nowrap;
}

.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.5rem;
}

.nav-toggle span {
  width: 22px;
  height: 2px;
  background: var(--text);
  display: block;
}

/* The pill nav needs room for 8 items plus the logo, social buttons and CTA —
   below this it collapses to the hamburger dropdown instead. */
@media (max-width: 1100px) {
  .main-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
    background: var(--surface);
    padding: 1.5rem;
    border: none;
    border-radius: 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    backdrop-filter: none;
    display: none;
  }
  .main-nav.open { display: flex; }
  .header-cta { display: none !important; }
  .nav-toggle { display: flex; }
}

/* Below this the header bar has no room for the social buttons next to the
   logo and hamburger. */
@media (max-width: 560px) {
  .social-icons { display: none; }
}

/* ============ hero (Home + inner pages) ============ */
.hero {
  position: relative;
  padding: 5rem 1.5rem 4rem;
  text-align: center;
  overflow: hidden;
}

.hero .orbit { opacity: 0.22; }

.hero--inner {
  padding: 3.5rem 1.5rem 3rem;
}

.hero--inner .orbit {
  width: min(50vh, 420px);
  height: min(50vh, 420px);
  opacity: 0.14;
}

.hero-content {
  position: relative;
  z-index: 1;
  max-width: 720px;
  margin: 0 auto;
}

/* ============ Home hero: split layout - copy left, card stack right ============ */
.hero--split {
  position: relative;
  display: block;
  padding: 0;
  max-width: none;
  /* Pulls up behind the 80px header (see .header-inner) so the ambient wash
     runs edge-to-edge behind the nav, which floats over it. */
  margin: -80px 0 0;
  text-align: left;
  background: var(--ink);
  overflow: hidden;
}

/* Three offset radial washes standing in for off-screen red light sources.
   Layered rather than one gradient so the bloom peaks behind the card stack on
   the right and falls away unevenly, the way a lit set does. */
.hero-ambient {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(58% 52% at 76% 16%, rgba(255, 74, 61, 0.26), transparent 70%),
    radial-gradient(46% 46% at 6% 86%, rgba(142, 28, 22, 0.34), transparent 72%),
    radial-gradient(95% 65% at 50% 0%, rgba(217, 45, 36, 0.10), transparent 68%);
}

.hero-grid {
  position: relative;
  z-index: 1;
  max-width: 1200px;
  margin: 0 auto;
  /* top padding clears the 80px header this section is pulled underneath */
  padding: calc(80px + 4rem) 1.5rem 4.5rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
  gap: 3.5rem;
  align-items: center;
}

.hero--split .hero-content {
  position: relative;
  z-index: 1;
  max-width: 600px;
  margin: 0;
  padding: 0;
}

.hero-cards {
  display: grid;
  gap: 1.15rem;
}

@media (max-width: 1000px) {
  .hero-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 2.75rem;
    padding: calc(80px + 3rem) 1.5rem 3.5rem;
  }

  .hero--split .hero-content { max-width: 100%; }

  .hero-cards {
    width: 100%;
    max-width: 420px;
  }
}

/* ============ hero card 1: stat slider ============ */
.stat-slider {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: 26px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: var(--surface);
}

.stat-slide {
  position: absolute;
  inset: 0;
  margin: 0;
}

/* Hiding is gated behind .js-enabled, which script.js adds. Without JS the
   slides stack in one absolutely-positioned box and the last one stays
   readable; if the hiding lived in the base rule, a JS failure would leave an
   empty card. visibility (not just opacity) is what actually takes an inactive
   slide out of the accessibility tree, and unlike display it can be deferred
   with a transition-delay so the crossfade finishes first. */
.stat-slider.js-enabled .stat-slide {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.6s ease, visibility 0s linear 0.6s;
}

.stat-slider.js-enabled .stat-slide.is-active {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.6s ease, visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .stat-slider.js-enabled .stat-slide,
  .stat-slider.js-enabled .stat-slide.is-active {
    transition: none;
  }
}

.stat-slide img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Bottom scrim for the caption, plus a red/violet wash so warm business stock
   picks up some of the lit-from-the-side quality this layout is built around. */
.stat-slide::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(10, 5, 6, 0.95) 0%, rgba(10, 5, 6, 0.55) 34%, rgba(10, 5, 6, 0.04) 64%),
    linear-gradient(150deg, rgba(217, 45, 36, 0.30), rgba(40, 14, 46, 0.20) 62%, transparent);
}

.stat-slide-body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 1.6rem;
}

.stat-figure {
  font-family: var(--font-display);
  font-size: clamp(3rem, 4.8vw, 4.25rem);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.04em;
  margin: 0 0 0.65rem;
  color: #fff;
}

.stat-figure-suffix {
  color: rgba(255, 255, 255, 0.42);
  font-weight: 600;
}

.stat-slide-caption {
  margin: 0;
  font-size: 1rem;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.80);
  max-width: 25ch;
}

.stat-slider-progress {
  position: absolute;
  top: 1.35rem;
  left: 1.35rem;
  right: 1.35rem;
  z-index: 2;
  display: flex;
  gap: 0.45rem;
}

.stat-slider-progress button {
  flex: 1;
  position: relative;
  height: 3px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.30);
  cursor: pointer;
  transition: background 0.3s ease;
}

/* The bar is 3px for looks; this grows the pointer/touch target to 23px tall
   without changing what is drawn. */
.stat-slider-progress button::before {
  content: '';
  position: absolute;
  inset: -10px 0;
}

.stat-slider-progress button[aria-selected="true"] {
  background: #fff;
}

.stat-slider-progress button:focus-visible {
  outline: 2px solid var(--accent-hot);
  outline-offset: 4px;
}

/* ============ hero card 2: client logo marquee ============ */
.partner-card {
  position: relative;
  border-radius: 22px;
  background: var(--surface);
  padding: 1.4rem;
  overflow: hidden;
  box-shadow: 0 -14px 44px -20px rgba(255, 74, 61, 0.55);
}

/* Border-only gradient: a 1px padding ring masked so only the frame paints,
   giving a lit top edge that fades down the sides. A plain border cannot do
   this because borders take a single flat colour. */
.partner-card::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(180deg, rgba(255, 74, 61, 0.9), rgba(255, 255, 255, 0.10) 22%, rgba(255, 255, 255, 0.05));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}

.partner-card-title {
  font-family: var(--font-display);
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 1.1rem;
  color: var(--text);
}

.logo-marquee {
  display: grid;
  gap: 0.9rem;
}

.logo-marquee-row {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}

.logo-marquee-track {
  display: flex;
  align-items: center;
  width: max-content;
  animation: logo-scroll 30s linear infinite;
}

.logo-marquee-row--reverse .logo-marquee-track {
  animation-direction: reverse;
}

/* Forced to a single white silhouette. Measured mean luminance of the opaque
   pixels runs from 0.4 (Free Wowta) to 158 (Bolsheviks Party) across the six
   marks, so three of them are invisible on this card if shown as-is.
   brightness(0) flattens every colour to black, invert(1) lifts it to white;
   alpha is untouched, so the mark keeps its shape. */
/* 48px of CANVAS, not of mark. Each logo sits on an identical 320x128 canvas
   and its trimmed mark fills between 43% (Free Wowta) and 88% (Bolsheviks) of
   that height -- they were normalised to equal optical AREA, not equal height,
   so a wide short mark and a tall narrow one carry the same weight. At the
   previous 30px the marks rendered 13-26px tall and read as smudges. */
.logo-marquee-track img {
  height: 48px;
  width: auto;
  flex-shrink: 0;
  /* Spacing is per-item, not flex `gap`. With `gap`, N items have only N-1
     gaps, so half of the doubled track is one gap short of a whole repeat and
     the translateX(-50%) loop jumps by that much every cycle. A per-item
     margin makes the period exactly (item + margin), so half the track is
     exactly one set. */
  margin-right: 2rem;
  filter: brightness(0) invert(1);
  opacity: 0.7;
}

/* The Bolsheviks mark is a solid filled roundel: only 9.6% of its opaque
   pixels are soft-edged, against 35-71% for the other five, so flattening it
   to a silhouette leaves a blank white disc. Greyscale keeps its internal
   structure while still reading as monochrome alongside the rest. */
.logo-marquee-track img[src*="bolsheviks"] {
  filter: grayscale(1) brightness(1.3);
}

@keyframes logo-scroll {
  to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .logo-marquee-track { animation: none; }
}

/* ============ eyebrow chip ============ */
/* Same specificity as .eyebrow, so this must stay below it in the file. */
.eyebrow--chip {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 1.05rem 0.5rem 0.9rem;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  backdrop-filter: blur(8px);
  color: var(--text);
  letter-spacing: 0.12em;
}

.eyebrow--chip::before {
  content: '';
  width: 7px;
  height: 7px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent-hot);
  box-shadow: 0 0 0 3px rgba(255, 74, 61, 0.20);
}

/* ============ buttons ============ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9375rem;
  text-decoration: none;
  padding: 0.75rem 1.5rem;
  border-radius: 999px;
  border: none;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.btn-primary {
  /* White, not --ink. The label is 15px/600 so it needs 4.5:1; near-black on
     this red is 4.13:1 (and was 3.64:1 on the previous palette), while white
     on it is 4.83:1. */
  color: #fff;
  background: var(--accent);
  box-shadow: 0 8px 30px rgba(255, 74, 61, 0.25);
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 36px rgba(255, 74, 61, 0.4);
}

/* ============ cards ============ */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.5rem;
}

.card {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 2rem;
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

.card:hover {
  transform: translateY(-4px);
  /* accent-hot reads as a rim light on near-black. The cream-section override
     (.section-alt .card:hover) deliberately stays on --accent, which is 4.2:1
     on cream where accent-hot is only 3.0:1. */
  border-color: rgba(255, 74, 61, 0.5);
  box-shadow: 0 18px 48px -22px rgba(255, 74, 61, 0.55);
}

.card h3 {
  font-family: var(--font-display);
  font-size: 1.125rem;
  margin: 0 0 0.75rem;
}

.card p {
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.6;
  margin: 0;
}

/* ============ footer ============ */
.site-footer {
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  padding-top: 3rem;
  position: relative;
  z-index: 1;
  overflow: hidden;
}

.footer-watermark {
  position: absolute;
  left: 50%;
  bottom: -3rem;
  transform: translateX(-50%);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(4rem, 14vw, 11rem);
  line-height: 1;
  white-space: nowrap;
  color: rgba(255, 255, 255, 0.04);
  pointer-events: none;
  z-index: 0;
}

.footer-inner,
.footer-bottom {
  position: relative;
  z-index: 1;
}

.footer-inner {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 2rem;
  padding-bottom: 2.5rem;
}

.footer-logo .logo-img { height: 32px; }
.footer-tagline { color: var(--muted); font-size: 0.875rem; margin-top: 0.75rem; }

.footer-col h4 {
  font-family: var(--font-label);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  color: var(--muted);
  margin: 0 0 1rem;
}

.footer-links, .footer-contact {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.footer-links a, .footer-contact a {
  color: var(--text);
  text-decoration: none;
  font-size: 0.9375rem;
}

.footer-links a:hover, .footer-contact a:hover { color: var(--accent-hot); }

.footer-area { color: var(--muted); font-size: 0.9375rem; margin: 0; }

.footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  padding: 1.5rem 0;
  text-align: center;
  color: var(--muted);
  font-size: 0.8125rem;
}

/* ============ scroll reveal ============ */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

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

@media (prefers-reduced-motion: reduce) {
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .main-nav a, .btn, .card, .social-icon {
    transition: none;
  }
}

/* ============ contact form ============ */
.contact-form {
  max-width: 560px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.form-field label {
  font-family: var(--font-label);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.form-field input,
.form-field textarea {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 8px;
  padding: 0.75rem 1rem;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 0.9375rem;
}

.form-field input:focus,
.form-field textarea:focus {
  outline: 2px solid var(--accent-hot);
  outline-offset: 2px;
}

.form-field.honeypot {
  position: absolute;
  left: -9999px;
  top: -9999px;
}

.form-success {
  display: none;
  /* Amber, not the brand red. --accent is now a neon red, which put the
     success notice and the error notice (below) within a few degrees of hue
     of each other. */
  background: rgba(232, 163, 61, 0.12);
  border: 1px solid rgba(232, 163, 61, 0.45);
  border-radius: 8px;
  padding: 1rem 1.25rem;
  color: var(--text);
  font-size: 0.9375rem;
}

.form-success.visible { display: block; }

/* Glyph prefixes so the two notices differ by more than hue - required
   regardless of the colours, since colour alone cannot carry meaning. */
.form-success::before,
.form-error::before {
  font-weight: 700;
  margin-right: 0.6rem;
}

.form-success::before {
  content: '\2713';
  color: var(--star);
}

.form-error::before {
  content: '\0021';
  color: var(--accent-hot);
}

.form-error {
  display: none;
  background: rgba(217, 45, 36, 0.14);
  border: 1px solid rgba(217, 45, 36, 0.5);
  border-radius: 8px;
  padding: 1rem 1.25rem;
  color: var(--text);
  font-size: 0.9375rem;
}

.form-error.visible { display: block; }

/* ============ network map (Home hero signature element) ============ */
.network-map {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  opacity: 0.9;
  pointer-events: none;
  z-index: 0;
}

.network-map .net-path {
  fill: none;
  stroke: url(#netGradient);
  stroke-width: 2;
  stroke-linecap: round;
  opacity: 0.5;
  stroke-dasharray: 300;
  stroke-dashoffset: 300;
  animation: draw-path 1.6s ease-out forwards;
}

.network-map .net-node circle {
  fill: url(#netGradient);
  animation: node-pulse 2.4s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}

.network-map .net-node text {
  font-family: var(--font-label);
  font-size: 13px;
  fill: var(--muted);
  letter-spacing: 0.05em;
}

@keyframes draw-path {
  to { stroke-dashoffset: 0; }
}

@keyframes node-pulse {
  0%, 100% { opacity: 0.6; r: 5; }
  50% { opacity: 1; r: 7; }
}

@media (prefers-reduced-motion: reduce) {
  .network-map .net-path {
    stroke-dashoffset: 0;
    animation: none;
  }
  .network-map .net-node circle {
    animation: none;
    opacity: 1;
  }
}

/* Below ~480px the hero's own box flips from landscape to portrait (text
   wraps enough that hero height exceeds hero width), so the height:100%/
   width:100% square above ends up vertically centered mid-hero and its
   node ring lands on top of the headline/subhead text. Rather than chase
   exact text-line coordinates on every narrow phone size, shrink the whole
   map into a small badge that lives entirely inside the fixed 80px
   padding-top gap above the eyebrow (always blank, always text-free) --
   safe by construction regardless of exact width. Labels are dropped at
   this size since the same 5 country names are already spelled out in the
   subhead and markets list. */
@media (max-width: 480px) {
  .network-map {
    top: 4px;
    left: 50%;
    width: 72px;
    height: 72px;
    transform: translateX(-50%);
  }

  .network-map .net-path {
    stroke-width: 16;
  }

  /* !important is required here: the node-pulse keyframe animation (see
     above) animates the `r` property between 5 and 7 on every circle, and a
     running CSS animation overrides plain (non-!important) declarations for
     any property it animates for its entire duration -- a same-specificity
     override without !important is silently inert. !important is the one
     thing that wins over an animation per the cascade, so it's needed to
     actually enlarge the node dots at this size. */
  .network-map .net-node circle {
    r: 24 !important;
  }

  .network-map .net-node text {
    display: none;
  }
}

/* ============ stats strip ============ */
.stats-strip {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 3rem;
}

.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.stat-number {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 5vw, 3.5rem);
  color: var(--accent-hot);
  line-height: 1;
}

.stat-label {
  margin-top: 0.5rem;
  font-family: var(--font-label);
  font-size: 0.8125rem;
  letter-spacing: 0.05em;
  color: var(--muted);
  text-transform: uppercase;
}

/* ============ case-study browser-chrome frame ============ */
.browser-frame {
  position: relative;
  border-radius: 8px;
  overflow: hidden;
}

.browser-frame-bar {
  display: flex;
  gap: 6px;
  padding: 8px 10px;
  background: rgba(255, 255, 255, 0.05);
}

.browser-frame-bar span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
}

.browser-frame img {
  display: block;
  width: 100%;
  height: auto;
}

.frame-tags {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  padding: 0.75rem;
  background: linear-gradient(to top, rgba(15, 7, 9, 0.92), transparent);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.browser-frame:hover .frame-tags {
  opacity: 1;
  transform: translateY(0);
}

.frame-tags span {
  font-family: var(--font-label);
  font-size: 0.6875rem;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
}

@media (prefers-reduced-motion: reduce) {
  .frame-tags { transition: none; }
}

/* ============ about page pull-quote ============ */
.pull-quote {
  position: relative;
  margin: 0 0 2rem;
  padding-left: 1.75rem;
  border-left: 3px solid var(--accent);
  font-family: var(--font-display);
  font-size: 1.375rem;
  line-height: 1.6;
  color: var(--text);
}

/* ============ photography (duotone brand treatment) ============ */
.photo-frame {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
}

.photo-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.photo-frame::after {
  content: '';
  position: absolute;
  inset: 0;
  /* --accent-deep as the warm stop: multiply already darkens, so the bright
     fill red flattens into a red cast instead of reading as a duotone. */
  background: linear-gradient(135deg, rgba(15, 7, 9, 0.55) 0%, rgba(142, 28, 22, 0.45) 100%);
  mix-blend-mode: multiply;
  pointer-events: none;
}

.about-photo {
  height: clamp(220px, 40vw, 380px);
}

/* services page: alternating text + photo rows */
.service-row {
  display: flex;
  align-items: center;
  gap: 3rem;
}

.service-row > * {
  flex: 1 1 320px;
}

.service-row--reverse {
  flex-direction: row-reverse;
}

.service-row .photo-frame {
  height: clamp(220px, 28vw, 320px);
}

@media (max-width: 720px) {
  .service-row,
  .service-row--reverse {
    flex-direction: column;
  }
}

/* ============ pricing ============ */
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 2rem;
  max-width: 900px;
  margin: 0 auto;
}

.pricing-card {
  position: relative;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 16px;
  padding: 2.5rem 2rem;
  display: flex;
  flex-direction: column;
}

.pricing-card--featured {
  border-color: rgba(255, 74, 61, 0.5);
  background: var(--surface-2);
}

.pricing-badge {
  position: absolute;
  top: -0.75rem;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-label);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
  background: var(--accent);
  color: #fff;
  padding: 0.35rem 0.9rem;
  border-radius: 999px;
  white-space: nowrap;
}

.pricing-name {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  margin: 0 0 0.5rem;
}

.pricing-price {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2.75rem;
  line-height: 1;
  margin-bottom: 0.5rem;
  color: var(--accent-hot);
}

.pricing-price span {
  font-family: var(--font-label);
  font-size: 0.875rem;
  font-weight: 500;
  -webkit-text-fill-color: var(--muted);
  color: var(--muted);
}

.pricing-desc {
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.6;
  margin: 0 0 1.5rem;
}

.pricing-features {
  list-style: none;
  padding: 0;
  margin: 0 0 2rem;
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.pricing-features li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-size: 0.9375rem;
  color: var(--text);
  line-height: 1.4;
}

.pricing-features li::before {
  content: '\2713';
  color: var(--accent-hot);
  font-weight: 700;
  flex-shrink: 0;
}

.pricing-note {
  text-align: center;
  color: var(--muted);
  font-size: 0.8125rem;
  margin-top: 2.5rem;
}

/* ============ marquee ticker (section divider) ============ */
.marquee {
  position: relative;
  overflow: hidden;
  background: var(--ink-2);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  padding: 1.3rem 0;
  transform: skewY(-1deg);
  margin: -0.5rem 0;
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee-scroll 22s linear infinite;
  transform: skewY(1deg);
}

.marquee-track span {
  display: inline-flex;
  align-items: center;
  gap: 1.25rem;
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.9vw, 1.35rem);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
  padding: 0 1.4rem;
  white-space: nowrap;
}

.marquee-track span::after {
  content: '\2726';
  font-size: 0.7em;
  color: var(--accent-hot);
}

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
  }
}

/* ============ Home hero photo + corner stat ============ */
.hero-photo {
  position: relative;
  max-width: 480px;
  margin: 2.5rem auto 0;
  border-radius: 16px;
  overflow: hidden;
}

.hero-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-stat-badge {
  position: absolute;
  bottom: 1rem;
  right: 1rem;
  background: rgba(15, 7, 9, 0.85);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 12px;
  padding: 0.75rem 1.25rem;
  text-align: center;
}

.hero-stat-badge .stat-number {
  font-size: 1.75rem;
}

.hero-stat-badge .stat-label {
  font-size: 0.625rem;
}

.hero--inner .hero-photo {
  position: absolute;
  top: 0.5rem;
  right: 1.5rem;
  max-width: 180px;
  opacity: 0.5;
  pointer-events: none;
  z-index: 0;
}

.hero--inner .hero-photo .hero-stat-badge {
  display: none;
}

@media (max-width: 720px) {
  .hero--inner .hero-photo {
    display: none;
  }
}

/* ============ portfolio hover-reveal caption ============ */
.portfolio-hover-caption {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 1.25rem 1.25rem 3.5rem;
  background: linear-gradient(to top, rgba(15, 7, 9, 0.88), transparent 60%);
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
}

.browser-frame:hover .portfolio-hover-caption {
  opacity: 1;
}

.portfolio-hover-caption .cat {
  font-family: var(--font-label);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* --accent-hot, not --accent: this caption is 11px on a dark scrim, where
     --accent is 4.13:1 (under the 4.5 bar) and --accent-hot is 5.97:1. */
  color: var(--accent-hot);
  margin-bottom: 0.35rem;
}

.portfolio-hover-caption .view-link {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--text);
}

@media (prefers-reduced-motion: reduce) {
  .portfolio-hover-caption { transition: none; }
}

/* ============ testimonial carousel ============ */
.testimonial-carousel {
  position: relative;
  max-width: 640px;
  margin: 0 auto;
  padding: 3rem 1.5rem;
  border-radius: 16px;
  background-color: var(--surface);
  background-image: radial-gradient(rgba(255, 255, 255, 0.08) 1px, transparent 1px);
  background-size: 18px 18px;
  text-align: center;
}

/* No base display:none here by design: without JS, all slides should render
   (progressive enhancement -- see script.js, which hides all but the first
   slide once it runs, and toggles .active to page through the rest). */

.testimonial-slide p {
  font-family: var(--font-display);
  font-size: 1.25rem;
  line-height: 1.6;
  color: var(--text);
  margin: 0 0 1.5rem;
}

.testimonial-slide h3 {
  font-size: 1rem;
  margin: 0;
}

/* Must be scoped under .testimonial-slide: a bare .testimonial-source (0,1,0)
   loses to .testimonial-slide p (0,1,1) above, which would render this caption
   as 1.25rem body copy. */
.testimonial-slide .testimonial-source {
  font-family: var(--font-label);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0.75rem 0 0;
}

.testimonial-nav {
  display: flex;
  justify-content: center;
  gap: 1rem;
  margin-top: 2rem;
}

.testimonial-nav button {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.2);
  background: transparent;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.125rem;
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease;
}

.testimonial-nav button:hover {
  /* 18px non-bold arrows need 4.5:1; --accent gives 4.13 on this surface. */
  border-color: var(--accent-hot);
  color: var(--accent-hot);
}

@media (prefers-reduced-motion: reduce) {
  .testimonial-nav button { transition: none; }
}

/* ============ dark-surfaced components: reassert dark-context tokens ============
   .testimonial-carousel, .frame-tags, and .portfolio-hover-caption all paint their
   OWN dark background regardless of section. .section-alt (see above) overrides the
   --text/--muted custom properties to dark-ink values for cream-background sections,
   and those custom properties inherit down the DOM -- so when any of these three
   components lands inside a .section-alt ancestor (as they do on index.html), they
   were inheriting dark-ink text colors and rendering near-invisible against their
   own dark backgrounds. Re-assert the dark-context tokens here so these components
   stay legible no matter what section they're placed in. */
.testimonial-carousel,
.frame-tags,
.portfolio-hover-caption {
  --text: var(--text-on-dark);
  --muted: var(--muted-on-dark);
  color: var(--text);
}

/* ============ trusted-by client logo strip ============ */
.logo-strip {
  display: grid;
  /* Fixed counts rather than auto-fit: 6 logos divide evenly by 3 and by 2,
     so neither breakpoint can leave a stranded orphan row. */
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}

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

/* Each logo gets its own light tile. These six client marks range from
   near-white to near-black, so no single section background keeps them all
   legible — a white surface per tile is the only treatment that works for
   every one without recolouring someone's brand. */
.logo-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  border-radius: 14px;
  padding: 1.25rem;
}

/* Each logo is pre-rendered onto an identical 320x128 canvas, trimmed of its
   transparent padding and scaled to equal optical area, so one width rule
   keeps all six balanced. Sizing them individually in CSS cannot work: the
   square marks would height-cap to a fraction of the wide ones' footprint. */
.logo-tile img {
  display: block;
  width: 100%;
  height: auto;
}

/* ============ cream statement section ============ */
.statement {
  text-align: center;
}

.statement-text {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 4.2vw, 3rem);
  line-height: 1.25;
  letter-spacing: -0.01em;
  max-width: 900px;
  margin: 0 auto;
}

.statement-text .accent-italic {
  color: var(--accent);
}

.statement-sub {
  max-width: 640px;
  margin: 2rem auto 0;
  font-size: 1.0625rem;
  line-height: 1.8;
  color: var(--muted);
}

/* ============ aggregate Google rating ============ */
/* A dark chip, even though it sits in a cream section: --star amber is only
   1.88:1 on cream. Keeping the badge dark means stars stay one colour
   everywhere they appear, rather than needing a cream-context variant. */
.rating-summary {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.3rem 0.85rem;
  width: fit-content;
  margin: -1rem auto 2.75rem;
  padding: 0.85rem 1.6rem;
  background: var(--ink);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  --text: var(--text-on-dark);
  --muted: var(--muted-on-dark);
  color: var(--text);
}

.rating-score {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.5rem;
  line-height: 1;
}

.rating-stars {
  color: var(--star);
  letter-spacing: 0.12em;
  font-size: 1rem;
}

.rating-count {
  font-family: var(--font-label);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ============ review stars + source line ============ */
.testimonial-stars {
  display: block;
  color: var(--star);
  letter-spacing: 0.18em;
  font-size: 1rem;
  margin-bottom: 1.25rem;
}


/* ============ numbered service rows ============ */
.service-rows {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}

.service-row {
  border-bottom: 1px solid var(--line);
}

.service-row a {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.4rem 2rem;
  padding: 1.85rem 1.25rem;
  text-decoration: none;
  color: inherit;
  transition: padding-left 0.3s ease;
}

/* The wash is a sibling layer rather than a background so it can fade
   independently of the padding shift. It is absolutely positioned, so it would
   paint over the static children -- hence the position: relative below. */
.service-row a::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(217, 45, 36, 0.16), transparent 65%);
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

.service-row a:hover::before,
.service-row a:focus-visible::before {
  opacity: 1;
}

.service-row a > * {
  position: relative;
}

.service-row a:hover,
.service-row a:focus-visible {
  padding-left: 2rem;
}

.service-row-num {
  align-self: start;
  padding-top: 0.4rem;
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--accent-hot);
}

.service-row-main {
  display: grid;
  gap: 0.4rem;
}

.service-row-title {
  font-family: var(--font-display);
  font-size: clamp(1.375rem, 2.6vw, 2rem);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--text);
}

.service-row-desc {
  font-size: 1rem;
  line-height: 1.6;
  color: var(--muted);
  max-width: 56ch;
}

.service-row-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  font-size: 1.05rem;
  color: var(--text);
  transition: transform 0.3s ease, background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease;
}

.service-row a:hover .service-row-arrow,
.service-row a:focus-visible .service-row-arrow {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  transform: translateX(6px);
}

@media (max-width: 640px) {
  .service-row a {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0.35rem 1rem;
    padding: 1.5rem 0.5rem;
  }

  /* The arrow is hover affordance only; on touch the whole row is the target. */
  .service-row-arrow { display: none; }

  .service-row a:hover,
  .service-row a:focus-visible { padding-left: 1rem; }
}

@media (prefers-reduced-motion: reduce) {
  .service-row a,
  .service-row a::before,
  .service-row-arrow { transition: none; }

  .service-row a:hover,
  .service-row a:focus-visible { padding-left: 1.25rem; }
}
