* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* Every image on this page already sets its own width via a class
   (.op-card__image, .conversion__media-image, etc.), so this changes
   nothing today — it's the same safety net every other page stylesheet
   has, in case an <img> is ever added here without one. */
img { display: block; max-width: 100%; }

/* Every other page stylesheet sets this; index.html was missing it, so its
   same-page anchor jumps (e.g. Products pills) were a hard instant cut
   instead of the smooth scroll used everywhere else on the site. */
html {
  scroll-behavior: smooth;
}

body {
  background-color: #000000;
  font-family: 'Georgia', serif;
  overflow-x: hidden;
}

/* Matches the .skip-link on services/website/marketing, which define it in
   their own stylesheets. Literal values here because style.css carries no
   design tokens. Inverted (white on black) since this page's ground is black. */
.skip-link {
  position: absolute;
  top: -80px;
  left: 16px;
  z-index: 300;
  padding: 16px 24px;
  background: #ffffff;
  color: #111111;
  border-radius: 4px;
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-size: 14px;
  text-decoration: none;
}

.skip-link:focus {
  top: 16px;
}

/* Header styles (.site-header, .logo, .site-nav, .products-menu,
   .contact-btn) now live in css/header.css, shared with every page. */


/* ==========================================================================
   CLOSING FRAME — particle network

   Ported from a React/canvas reference the client supplied (nodes drifting
   inside the frame, connected by lines when close, repelled by the pointer).
   This project has no build step and no framework (see script.js for the
   full reasoning), so the mechanics are reimplemented in plain Canvas2D as
   createParticleNetwork() — same visual result, zero new dependencies.

   Recolored from the reference's purple to this site's own accent pair
   (#88bcd8 / #f3ffc1, the same two colors used on the AI Website Builder
   card's dot grid and eyebrow) so the section joins the site's palette
   instead of introducing a color that appears nowhere else on the page.
   ========================================================================== */

.hero {
  position: relative;
  width: 100%;
  /* svh after vh: unsupporting browsers discard the second line and keep
     the first; supporting ones get the mobile-toolbar-visible height rather
     than the taller, toolbar-hidden 100vh. dvh last: it tracks the toolbar
     live as it shows/hides while scrolling, instead of committing to one
     fixed value for the whole page load. Without it, a static svh measured
     while the toolbar happened to be hidden can leave this section (and
     everything after it, including the footer) sized taller than the
     toolbar-shown viewport ever needs — which reads as extra blank
     scroll room past the footer on some mobile browsers. */
  min-height: 100vh;
  min-height: 100svh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 160px 24px 120px;
  gap: 40px;
  overflow: hidden;
  background-color: #000000;
}

.hero__canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  display: block;
}

@media (min-width: 1440px) {
  .hero {
    padding: 240px 24px 80px;
  }
}

.hero__title {
  position: relative;
  z-index: 1;
  max-width: 900px;
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 300;
  letter-spacing: -0.06em;
  line-height: 1.04;
  color: #ffffff;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-size: clamp(38px, .920455rem + 7.27273vw, 42px);
}

.hero__title-line,
.hero__rotating {
  white-space: nowrap;
}

@media (min-width: 375px) {
  .hero__title {
    font-size: clamp(42px, 1.98984rem + 2.71003vw, 52px);
  }
}

/* 768px, not 744 — matches the rest of the site's tablet breakpoint (see
   css/website.css etc.) rather than a homepage-only number. */
@media (min-width: 768px) {
  .hero__title {
    font-size: clamp(52px, 2.57609rem + 1.44928vw, 56px);
  }
}

/* 1024px, not 1020 — matches the rest of the site's desktop breakpoint. */
@media (min-width: 1024px) {
  .hero__title {
    font-size: clamp(56px, 2.51923rem + 1.53846vw, 60px);
  }
}

@media (min-width: 1280px) {
  .hero__title {
    font-size: clamp(60px, 1.75rem + 2.5vw, 64px);
  }
}

@media (min-width: 1440px) {
  .hero__title {
    font-size: clamp(64px, 2.5rem + 1.66667vw, 72px);
  }
}

/* Same accent gradient as .ai-entry-card__eyebrow (line ~763) — white to
   #88bcd8 to #f3ffc1 and back — so the one word that changes on this section
   is tinted in the same two colors as the particle network behind it,
   instead of being an unrelated plain-white fade. */
.hero__rotating {
  display: inline-block;
  background: linear-gradient(90deg, #ffffff 29.44%, #88bcd8 39.97%, #f3ffc1 61.04%, #ffffff 71.57%);
  background-size: 300%;
  /* .ai-entry-card__eyebrow uses this gradient at the default 0% position,
     which shows only its leading (near-white) third — unnoticeable at 12px
     caption size. At headline size that same slice reads as plain white, so
     centered here instead: at 300% size, centering shows the gradient's
     middle third, which is exactly its #88bcd8-to-#f3ffc1 span. */
  background-position: 50% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  transition: opacity 0.25s ease;
}

.hero .contact-btn {
  position: relative;
  z-index: 1;
}

.hero__rotating.is-fading {
  opacity: 0;
}

/* Fade-up entrance, gated by the same IntersectionObserver that starts the
   canvas (script.js). Mirrors the AI card's staggered word reveal — an
   .is-visible class toggled per element with a small delay — rather than
   inventing a second animation convention. */
.hero__title,
.hero .contact-btn {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

.hero__title.is-visible,
.hero .contact-btn.is-visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .hero__title,
  .hero .contact-btn {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

.grow-section {
  width: 100%;
  min-height: 60vh;
  margin-top: 20px;
  padding: 120px 24px 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 48px;
  background-color: #ffffff;
}

.grow-headline {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: 700px;
}

.grow-headline__title {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 400;
  letter-spacing: -0.04em;
  line-height: 1.08;
  color: #111111;
  font-size: clamp(22px, 4vw + 12px, 50px);
}

.grow-headline__body {
  margin-top: 24px;
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 400;
  letter-spacing: -0.001em;
  line-height: 1.4;
  color: #111111;
  font-size: 16px;
}

.pills {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 4px;
  padding: 4px;
  list-style: none;
}

.pill-indicator {
  position: absolute;
  top: 4px;
  left: 0;
  height: calc(100% - 8px);
  width: 0;
  border-radius: 100px;
  background-color: rgba(0, 0, 0, 0.08);
  opacity: 0;
  pointer-events: none;
  transition: top 0.25s cubic-bezier(0.4, 0, 0.2, 1),
    left 0.25s cubic-bezier(0.4, 0, 0.2, 1),
    width 0.25s cubic-bezier(0.4, 0, 0.2, 1),
    height 0.25s cubic-bezier(0.4, 0, 0.2, 1),
    opacity 0.2s ease;
}

.pill-item {
  padding: 0 4px;
}

.pill {
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  position: relative;
  border: none;
  border-radius: 100px;
  padding: 12px 16px;
  background-color: transparent;
  color: #111111;
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-size: 15px;
  white-space: nowrap;
  scroll-margin-top: 140px;
}

.carousel-toolbar {
  width: 100%;
  max-width: 1200px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  padding: 0 24px;
  margin-bottom: -8px;
}

.carousel-control {
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  width: 30px;
  height: 30px;
  border: 1px solid #dddddd;
  border-radius: 30px;
  background-color: #ffffff4d;
  backdrop-filter: blur(10px);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.15s cubic-bezier(0.455, 0.03, 0.515, 0.955);
}

.carousel-control:hover {
  opacity: 0.6;
}

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

.carousel-control--prev {
  transform: rotate(90deg);
}

.carousel-control--next {
  transform: rotate(-90deg);
}

/* ==========================================================================
   Website showcase — 3D perspective carousel
   A vanilla port of a React/Tailwind reference (tilt + mouse-parallax
   carousel). No build step exists in this project, so behaviour is
   reproduced directly in CSS custom properties + script.js rather than via
   a component framework — see script.js for the render()/parallax logic.

   Cropping constraint: the reference sizes its image absolute inset-0
   w-[120%] h-[120%] object-cover, which (anchored top-left) crops ~17% off
   the right and bottom of every image. This site's screenshots have logos,
   nav links and stat rows flush against their edges (see the old
   .grow-carousel__image comment this replaces), so that crop would delete
   real content. Two layers are used instead: .wcar__backdrop is a blurred,
   heavily-cropped fill that carries the strong parallax (cropping doesn't
   matter on a blur), and .wcar__shot is the crisp screenshot at
   object-fit: contain with a small parallax range that can never clip it.
   ========================================================================== */

.wcar__stage {
  width: 100%;
  overflow: hidden;
  padding-block: 24px;
}

.wcar {
  width: 100%;
}

.wcar__track {
  display: flex;
  width: max-content;
  /* max-content, not the default auto: a flex container's block-level width
     resolves to fill its parent (.wcar) by default, which is far narrower
     than the sum of 8 slide widths. translateX(-N%) is computed against the
     track's OWN width, so with width:auto each step was only ~12.5% of
     .wcar's width — a few px — instead of one full slide. max-content sizes
     the track to its actual content (the reference gets the same effect via
     position:absolute, which is shrink-to-fit by default), restoring the
     percentage math the render() step in script.js assumes. */
  list-style: none;
  transition: transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
  will-change: transform;
}

.wcar__slide-wrap {
  flex-shrink: 0;
  perspective: 1200px;
}

.wcar__slide {
  width: min(78vw, 980px);
  margin-inline: 4vmin;
  transform: scale(0.98) rotateX(8deg);
  transform-origin: bottom;
  transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
  cursor: pointer;
}

.wcar__slide.is-current {
  transform: scale(1) rotateX(0deg);
  cursor: default;
}

.wcar__media {
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  overflow: hidden;
  background-color: #1d1f2f;
}

.wcar__backdrop {
  position: absolute;
  top: -10%;
  left: -10%;
  width: 120%;
  height: 120%;
  object-fit: cover;
  filter: blur(36px) brightness(0.6) saturate(1.1);
  opacity: 0.5;
  transition: opacity 0.6s ease-in-out;
  /* Strong parallax layer — translate3d(var(--x)/25, var(--y)/25, 0) set in
     script.js. Blurred and oversized, so travel never exposes an edge. */
}

.wcar__shot {
  position: absolute;
  top: 4%;
  left: 4%;
  width: 92%;
  height: 92%;
  object-fit: contain;
  opacity: 0.5;
  transition: opacity 0.6s ease-in-out;
  /* Gentle counter-parallax — translate3d(var(--x)/40, var(--y)/40, 0) in
     script.js. Max deflection is ~1.25% of card width against 4% of inset
     slack on every side, so the screenshot can never be cropped. */
}

.wcar__slide.is-current .wcar__backdrop,
.wcar__slide.is-current .wcar__shot {
  opacity: 1;
}

.wcar__controls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}

.wcar__arrow {
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  width: 40px;
  height: 40px;
  border: 1px solid #dddddd;
  border-radius: 40px;
  background-color: #ffffff4d;
  backdrop-filter: blur(10px);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.15s cubic-bezier(0.455, 0.03, 0.515, 0.955);
}

.wcar__arrow:hover {
  opacity: 0.6;
}

.wcar__arrow--prev {
  transform: rotate(90deg);
}

.wcar__arrow--next {
  transform: rotate(-90deg);
}

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

  .wcar__slide,
  .wcar__slide.is-current {
    transform: none;
    transition: none;
  }

  .wcar__backdrop,
  .wcar__shot {
    transform: none !important;
  }
}

.one-platform {
  width: 100%;
  padding: 80px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  background-color: #ffffff;
}

.op-headline {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: 700px;
  padding: 0 24px;
}

.op-headline__title {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 400;
  letter-spacing: -0.04em;
  line-height: 1.08;
  color: #111111;
  font-size: clamp(22px, 4vw + 12px, 50px);
}

.op-headline__body {
  margin-top: 24px;
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 400;
  letter-spacing: -0.001em;
  line-height: 1.4;
  color: #111111;
  font-size: 16px;
}

.op-carousel {
  width: 100%;
  max-width: 1200px;
  overflow-x: auto;
  scrollbar-width: none;
}

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

.op-carousel__track {
  display: flex;
  gap: 16px;
  list-style: none;
  padding: 0 24px;
}

.op-card {
  position: relative;
  flex-shrink: 0;
  width: 260px;
  aspect-ratio: 283 / 383;
  border-radius: 8px;
  background-color: #2f2f2f;
  padding: 24px;
  overflow: hidden;
}

/* Real artwork, filling the card exactly as the placeholder does */
.op-card__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Landscape source cropped to a portrait card — bias the crop toward the
   centre cards rather than the default midpoint. */
.op-card__image--payments {
  object-position: 52% 46%;
}

/* The typewriter sits in the right third — keep it in frame rather than
   the empty wood-grain centre the default crop lands on. */
.op-card__image--marketing-tools {
  object-position: 80% 42%;
}

/* The dashboard sits in the right third — bias the crop there so the
   screen survives the portrait cut rather than the keyboard. */
.op-card__image--analytics {
  object-position: 72% 50%;
}

/* The brightest cluster of circuitry sits in the left third — keep that
   in frame rather than the darker, more empty right edge. */
.op-card__image--design-intelligence {
  object-position: 34% 46%;
}

/* The search bar and its button run wider than the portrait crop keeps —
   nudge right so the "Search" button survives, and up slightly to the
   label/heading cluster rather than the empty grid below. */
.op-card__image--domains {
  object-position: 54% 42%;
}

/* Keeps the title and body legible over the artwork */
.op-card__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.55) 0%,
    rgba(0, 0, 0, 0.25) 38%,
    rgba(0, 0, 0, 0) 62%
  );
}

/* Same treatment as .grow-carousel__link — the anchor fills the card so the
   artwork is clickable, and repeats the card's 24px padding to keep the
   title and body where they were. */
.op-card__link {
  position: absolute;
  inset: 0;
  display: block;
  padding: 24px;
  color: inherit;
  text-decoration: none;
}

.op-card__content {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.op-card__title {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: #ffffff;
  font-size: 20px;
}

.op-card__body {
  max-width: 300px;
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  line-height: 1.4;
  color: #ffffff;
  font-size: 12px;
}

/* 768px, not 744 — matches the rest of the site's tablet breakpoint. */
@media (min-width: 768px) {
  .op-card {
    width: 300px;
  }
}

@media (min-width: 1280px) {
  .op-card {
    width: 310px;
  }
}

@media (min-width: 1440px) {
  .op-card {
    width: 350px;
  }
}

@media (min-width: 1920px) {
  .op-card {
    width: 430px;
  }
}

.get-started {
  position: relative;
  width: 100%;
  padding: 100px 24px 260px;
  background-color: #ffffff;
  overflow: hidden;
  mask-image: linear-gradient(to bottom, #000 0%, #000 calc(100% - 140px), transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 calc(100% - 140px), transparent 100%);
}

.get-started__gradient {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    #ffffff 0%,
    #fcfbfb 15%,
    #d6cfc6 30%,
    #9a8c7d 45%,
    #7a6f62 55%,
    #5c5349 65%,
    #3e3831 75%,
    #1f1c19 85%,
    #0a0909 100%
  );
  pointer-events: none;
}

.get-started__content {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 56px;
}

.get-started__headline {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: 600px;
}

.get-started__eyebrow {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 32px;
}

.ai-dot {
  border-radius: 100%;
  background-color: #111111;
}

.ai-dot--large {
  width: 10px;
  height: 10px;
}

.ai-dot--medium {
  width: 7px;
  height: 7px;
}

.ai-dot--small {
  width: 4px;
  height: 4px;
}

.get-started__title {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 400;
  letter-spacing: -0.04em;
  line-height: 1.08;
  color: #111111;
  font-size: clamp(22px, 4vw + 12px, 50px);
}

.get-started__body {
  margin-top: 24px;
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  letter-spacing: -0.001em;
  line-height: 1.4;
  color: #111111;
  font-size: 16px;
}

.ai-entry-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  /* Widened from 640px — a live site preview needs to read like a real
     desktop browser window, not a cropped thumbnail. */
  max-width: 960px;
  border-radius: 8px;
  background-color: #000000;
  text-decoration: none;
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(136, 188, 216, 0.12), 0 24px 64px rgba(136, 188, 216, 0.14);
  transition: box-shadow 0.3s ease;
}

.ai-entry-card:hover {
  box-shadow: 0 0 0 1px rgba(136, 188, 216, 0.22), 0 32px 80px rgba(136, 188, 216, 0.22);
}

.ai-entry-card__asset {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  /* Fallback if JS/the iframe doesn't run — matches the card's original look. */
  background: linear-gradient(135deg, #2a2a2a, #050505);
}

/* 1023px, not 743px. This was 743 and it silently broke the preview between
   744px and ~1000px — landscape phones, foldables and small tablets. Above
   743 the iframe stayed at its 1440px design width, so the embedded page saw
   a 1440px viewport, failed lily.js's own (max-width: 820px) test, and pulled
   the 2.9MB desktop hero video onto a mobile device. Measured at an 800px
   viewport before the fix: innerViewportWidth 1440, src hero.mp4.
   Keep this in sync with .ai-entry-card__site below — the two must agree, or
   the card's aspect-ratio and the iframe's design width disagree at some
   widths. (js/ai-preview-card.js used to carry a matching 1023px query for
   its mobile single-pass scrub; that behaviour was removed on request, so the
   preview now loops on every width and the JS no longer has a breakpoint.) */
@media (max-width: 1023px) {
  .ai-entry-card__asset {
    /* Below this width the card itself is too narrow to run the desktop
       preview at a legible scale (see .ai-entry-card__site below), so the
       whole box goes portrait instead — matches js/ai-preview-card.js
       switching the iframe to Lily's own mobile design width. */
    aspect-ratio: 3 / 4;
  }
}

.ai-entry-card__frame {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

/* The embedded site is laid out at a real desktop size and then scaled down
   with transform — not rendered small to begin with. A transform re-rasterises
   text at the composited scale, so it stays crisp; shrinking the iframe's own
   width/height would leave every font at a tiny native size and look blurry
   once the browser upscales it back visually. js/ai-preview-card.js measures
   .ai-entry-card__frame each resize and writes --preview-scale so the iframe
   always fills it exactly, at whichever design width is active. */
.ai-entry-card__site {
  position: absolute;
  top: 0;
  left: 0;
  width: 1440px;
  height: 900px;
  border: 0;
  transform: scale(var(--preview-scale, 0.625));
  transform-origin: top left;
  /* Preview only — the whole card is one link (#aiEntryCard) through to the
     AI builder, so clicks must pass through the iframe rather than land
     inside the embedded site. */
  pointer-events: none;
}

@media (max-width: 1023px) {
  .ai-entry-card__site {
    /* 390px is what the EMBEDDED document sees as its viewport, and that is
       the number that matters: lily.js switches to its mobile layout and its
       mobile hero video under 820px of iframe width. Because 390 < 820 this
       holds for the whole range below 1024px — which is the point, since the
       old 743px cutoff left 744-1023px serving the desktop video to phones
       and tablets. 390x520 keeps the 3:4 ratio above exact. */
    width: 390px;
    height: 520px;
  }
}

.ai-entry-card__overlay {
  position: absolute;
  inset: 0;
  /* Fades only the bottom ~18% into the card's black content block below —
     was transparent to 50%, which buried half of a live site preview under
     black. The site itself should stay fully visible, not screenshot-blurred
     and not obscured. */
  background: linear-gradient(to bottom, transparent 0%, transparent 82%, rgba(0, 0, 0, 0.85) 100%);
  pointer-events: none;
}

.ai-entry-card__content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
  padding: 16px 32px 40px;
  text-align: center;
}

.ai-entry-card__eyebrow {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  background: linear-gradient(90deg, #ffffff 29.44%, #88bcd8 39.97%, #f3ffc1 61.04%, #ffffff 71.57%);
  background-size: 300%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.ai-entry-card__title {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-size: 16px;
  line-height: 1.4;
  letter-spacing: -0.001em;
  color: #ffffff;
}

.ai-entry-card__title-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(6px);
}

.ai-entry-card__title-word.is-visible {
  animation: ai-word-in 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}

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

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .ai-entry-card__title-word {
    opacity: 1;
    transform: none;
  }

  .ai-entry-card__title-word.is-visible {
    animation: none;
  }
}

.ai-entry-card__cta {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 500;
  font-size: 18px;
  letter-spacing: -0.01em;
  color: #ffffff;
}

.conversion {
  width: 100%;
  /* svh after vh: unsupporting browsers discard the second line and keep
     the first; supporting ones get the mobile-toolbar-visible height rather
     than the taller, toolbar-hidden 100vh. dvh last: it tracks the toolbar
     live as it shows/hides while scrolling, instead of committing to one
     fixed value for the whole page load. Without it, a static svh measured
     while the toolbar happened to be hidden can leave this section (and
     everything after it, including the footer) sized taller than the
     toolbar-shown viewport ever needs — which reads as extra blank
     scroll room past the footer on some mobile browsers. */
  min-height: 100vh;
  min-height: 100svh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 48px;
  /* Extra bottom padding, not symmetric 24px. Content is centred in the
     padding box, so a heavier bottom pad lifts the whole stack — image,
     heading and CTA together — by roughly half the extra. That clearance is
     for mobile browsers whose URL bar is a pill FLOATING over the page:
     100svh already accounts for docked chrome, but nothing in CSS reports a
     floating overlay, so the CTA was landing underneath it. Desktop resets
     this via its own padding shorthand in the min-width:1024px block.
     min-height (not height) means if content ever exceeds the viewport the
     section grows and the page scrolls, rather than clipping the image. */
  padding: 24px 24px 120px;
  background-color: #000000;
  mask-image: linear-gradient(to bottom, transparent 0%, #000 140px, #000 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 140px, #000 100%);
}

.conversion__media {
  width: 100%;
  max-width: 760px;
}

.conversion__media-image {
  display: block;
  width: 100%;
  /* height:auto is load-bearing, not tidiness. This element is a <video>
     carrying width/height attributes, and the browser treats those as a
     presentational hint that beats aspect-ratio — so without this it
     renders 760x600 instead of square. The img{} reset above doesn't
     cover <video>. Same failure mode as .f5__shot in css/website.css. */
  height: auto;
  aspect-ratio: 1 / 1;
  border-radius: 12px;
  object-fit: cover;
  transform: translateY(-12px);
}

.conversion__text {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 24px;
  max-width: 480px;
}

.conversion__cta {
  align-self: center;
  /* Rounder than the shared .contact-btn 4px — this is the page's primary
     conversion button, and the pill shape sets it apart from the header's
     smaller Enquire button rather than reading as the same control twice. */
  border-radius: 100px;
}

.conversion__title {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-weight: 300;
  letter-spacing: -0.04em;
  line-height: 1.08;
  color: #ffffff;
  font-size: clamp(30px, 6vw, 48px);
}

.conversion__title-today {
  display: block;
  text-align: center;
}

/* 1024px, not 1020 — matches the rest of the site's desktop breakpoint. */
@media (min-width: 1024px) {
  .conversion {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 80px;
    padding: 24px 24px 24px 0;
  }

  .conversion__media {
    flex-shrink: 0;
  }

  .conversion__text {
    align-items: flex-start;
    text-align: left;
    max-width: 520px;
  }

  .conversion__media-image {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
  }
}

.footer {
  width: 100%;
  background-color: #000000;
  padding: 32px 24px 16px;
  display: flex;
  flex-direction: column;
  gap: 36px;
}

.footer__content {
  display: flex;
  flex-direction: column;
  gap: 36px;
}

.footer__auxiliary {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding-bottom: 36px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}

.footer__logo {
  height: 48px;
  width: auto;
}

.footer__tagline {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-size: 15px;
  letter-spacing: -0.001em;
  color: #ffffff;
}

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

.footer__column {
  display: flex;
  flex-direction: column;
  gap: 36px;
}

.footer__column-title {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-size: 13px;
  font-weight: 500;
  color: #ffffff;
}

.footer__column-list {
  display: flex;
  flex-direction: column;
  /* Spacing now lives in the links' own padding (below) so it doesn't
     double up with this gap. */
  gap: 0;
  list-style: none;
}

.footer__column-list a {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-size: 13px;
  color: #898989;
  text-decoration: none;
  transition: color 0.3s;
  /* WCAG 2.2 SC 2.5.8 (Target Size, Minimum) wants 24px; 18px matches the
     row height used on every other page's footer (.foot__list a). min-height
     (not padding) so the actual font metrics can't leave it a pixel short. */
  display: inline-flex;
  align-items: center;
  min-height: 32px;
}

.footer__column-list a:hover {
  color: #ffffff;
}

.footer__fineprint {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding-top: 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.25);
}

.footer__fineprint-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  list-style: none;
}

.footer__fineprint-list a {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-size: 13px;
  color: #898989;
  text-decoration: none;
  transition: color 0.3s;
  /* Matches .footer__column-list a's target-size treatment above — WCAG 2.2
     SC 2.5.8 wants 24px; min-height (not padding) so font metrics can't
     leave it a pixel short. */
  display: inline-flex;
  align-items: center;
  min-height: 32px;
}

.footer__fineprint-list a:hover {
  color: #ffffff;
}

.footer__copyright {
  font-family: 'Clarkson', 'Helvetica', sans-serif;
  font-size: 13px;
  color: #898989;
  text-align: center;
}

/* 768px, not 744 — matches the rest of the site's tablet breakpoint. */
@media (min-width: 768px) {
  .footer {
    padding: 32px 40px 16px;
  }

  .footer__links {
    grid-template-columns: repeat(4, 1fr);
    gap: 24px;
  }
}

/* 1024px, not 1020 — matches the rest of the site's desktop breakpoint. */
@media (min-width: 1024px) {
  .footer__content {
    flex-direction: row;
    align-items: flex-start;
    gap: 36px;
  }

  .footer__auxiliary {
    flex: 1;
    flex-direction: column;
    align-items: flex-start;
    padding-bottom: 0;
    border-bottom: 0;
  }

  .footer__links {
    flex: 2;
  }

  .footer__fineprint {
    flex-direction: row;
    justify-content: space-between;
  }
}


