/*
 * Our own overrides, loaded AFTER the October theme stylesheets so these win.
 *
 * Nothing here is part of the port — the theme CSS is copied verbatim by
 * `npm run import:october` and is overwritten on every run, so deliberate changes
 * to how the site behaves belong in this file instead. Keep each block commented
 * with what it changes and why.
 */

/* ---------------------------------------------------------------------------
 * Homepage hero: restyle the "Book Free Consultation" CTA now that it's a
 * next/link <a> instead of a <button> (fixing its dead data-october-onclick
 * handler). The theme's `.mainHeading button` rules (style.css ~line 261, plus
 * breakpoints at ~3818/4192/5004/5009) are tag-qualified to `button` only, so
 * they silently stopped applying to the <a> - it lost its white background and
 * rendered as near-invisible white-on-dark-navy text. Mirrored here against the
 * `.book-btn` class the link carries instead, at every breakpoint the theme
 * used.
 * ------------------------------------------------------------------------- */
.mainHeading .book-btn {
  color: var(--black);
  background-color: var(--white);
  border-color: var(--white);
  margin-top: 48px;
  padding: 20px 32px;
  font-weight: 700;
  font-size: 16px;
  font-family: var(--font-family-inter);
}

.mainHeading .book-btn:hover {
  color: var(--white);
  background-color: transparent;
  border-color: var(--white);
}

.mainHeading .book-btn svg {
  margin-right: 8px;
}

.mainHeading .book-btn:hover path {
  color: var(--white);
  fill: var(--white) !important;
}

@media (max-width: 1366px) {
  .mainHeading .book-btn {
    padding: 15px 22px;
    font-size: 15px;
  }
}

@media (max-width: 1200px) {
  .mainHeading .book-btn {
    margin-top: 35px;
  }
}

@media (max-width: 768px) {
  .mainHeading .book-btn svg {
    margin-right: 2px;
    width: 15px;
  }

  .mainHeading .book-btn {
    margin-top: 15px;
    padding: 5px 6px;
    font-size: 15px;
  }
}

/* Same tag-selector trap, same fix, for the homepage's "Got a Project or
 * Idea? -> Get in Touch" CTA: `.get_in_touch_section_div button` (style.css
 * ~line 542, plus the ~768px breakpoint at ~5167) only matched a real
 * <button>. Mirrored against the `.get-in-touch-btn` class that link carries
 * instead. */
.get_in_touch_section_div .get-in-touch-btn {
  background-color: #1c1e2c;
  color: var(--white);
  padding: 20px 32px;
  font-weight: 700;
  font-size: 16px;
  margin-top: 48px;
  line-height: 19px;
  font-family: var(--font-family-inter);
}

.get_in_touch_section_div .get-in-touch-btn:hover {
  background-color: transparent;
  border: 1px solid #1c1e2c;
}

.get_in_touch_section_div .get-in-touch-btn path {
  fill: var(--white);
}

.get_in_touch_section_div .get-in-touch-btn:hover path {
  fill: #1c1e2c;
}

@media (max-width: 768px) {
  .get_in_touch_section_div .get-in-touch-btn {
    padding: 8px 13px;
    margin-top: 35px;
    line-height: normal;
    font-size: 11px;
  }

  .get_in_touch_section_div .get-in-touch-btn svg {
    width: 15px;
  }
}

/* Same `.get_in_touch_section_div button` tag-selector trap (style.css:542,
 * plus the ~768px breakpoint at ~5167) as the homepage's CTA above, but for
 * every OTHER page's "get in touch" CTA band - `.get-in-touch-btn` above
 * only covers the class the homepage's link happens to carry. 8 AI Services
 * pages use `.ai-cta-btn` (some pairing it with a second `.btn-outline-light`
 * link) for this same band instead, and neither ever picked up the 48px/35px
 * top margin real <button>s get here - both buttons sat crammed directly
 * under the subtitle text with no gap, which is what "space between upper
 * text and them not proper" meant on the AI Chatbot page's "Ready To Build
 * Your AI Chatbot?" section.
 *
 * Targeting `a.btn` (Bootstrap's own base button class, present on every
 * link-styled-as-button in this codebase) rather than a specific class name
 * means this isn't tied to one more class that could be missed again -
 * `:not(.get-in-touch-btn)` just avoids double-declaring the identical 48px/
 * 35px values already set above for that one. */
.get_in_touch_section_div a.btn:not(.get-in-touch-btn) {
  margin-top: 48px;
}

@media (max-width: 768px) {
  .get_in_touch_section_div a.btn:not(.get-in-touch-btn) {
    margin-top: 35px;
  }
}

/* Same tag-selector trap, third time on this page, for the homepage's
 * "Explore All Projects" CTA: `.selected_works_section button` (style.css
 * ~line 592, plus the ~768px breakpoint at ~5190) only matched a real
 * <button> - most of it was just spacing/typography (the button's base color
 * comes from Bootstrap's `.btn-outline-dark`, which works on <a> already),
 * but `.selected_works_section button:hover path` (style.css ~line 601) is a
 * real contrast bug once missed: `.btn-outline-dark:hover` gives the button a
 * dark background, and this button's inline SVG has a hardcoded dark
 * `fill="#1C1E2C"` on its path, not `currentColor` - without this rule the
 * icon goes dark-on-dark (invisible) on hover. This CTA is reused verbatim
 * (same section, same class, same inline SVG) across ~29 portfolio pages and
 * several service pages, so one shared class + rule set here covers all of
 * them. */
.selected_works_section .explore-projects-btn {
  padding: 20px 32px;
  font-weight: 700;
  font-size: 16px;
  margin-top: 48px;
  line-height: 19px;
  font-family: var(--font-family-inter);
}

.selected_works_section .explore-projects-btn:hover path {
  fill: var(--white);
}

@media (max-width: 768px) {
  .selected_works_section .explore-projects-btn {
    padding: 10px 15px;
    font-size: 14px;
    margin-top: 40px;
  }

  .selected_works_section .explore-projects-btn svg {
    width: 18px;
  }
}

/* ---------------------------------------------------------------------------
 * Projects: show every project instead of three at a time.
 *
 * October ships `/projects` with `.all`, `.web` and `.mobile` set to
 * `display: none`, then reveals the first three per tab with
 * `$(".all").slice(0, 3).show()`. "Show more" then reveals them ONE at a time
 * (`hiddenItems.slice(0, 1).slideDown()`), so seeing all 21 projects on the live
 * site takes 18 clicks.
 *
 * These rules reveal them all up front. The category tabs still work — an
 * inactive `.tab-pane` hides its children regardless — so All / Mobile / Web
 * continue to filter; each just shows its full set now.
 *
 * To restore October's three-at-a-time behaviour, delete this block.
 * ------------------------------------------------------------------------- */
.projects-info.all,
.projects-info.web,
.projects-info.mobile {
  display: block !important;
}

/* The load-more buttons have nothing left to load once everything is visible. */
#all_load,
#web_load,
#mobile_load {
  display: none !important;
}

/* ---------------------------------------------------------------------------
 * Vbout forms (contact page + footer): keep Submit inside the gradient box when
 * validation fails.
 *
 * The theme gives `.get-project-form` `max-height: 930px` while its content is
 * 994px tall — the box silently clipped its own 72px bottom padding, leaving
 * ~18px under the Submit button. Vbout's validation then inserts a "Please check
 * the errors" line, a 24px "This field is required." under each empty field and
 * a GDPR message (~125px), pushing the button out of the box. Same on the live
 * site; visible as soon as Submit is clicked with empty fields.
 *
 *   1. Drop the max-height and trim the bottom padding by the 64px that was
 *      being clipped anyway, so the normal state is pixel-identical (930px) and
 *      the box can grow only when errors appear.
 *   2. Per-field errors are overlaid in the 24px gap between rows, and the
 *      summary line sits in the top padding — so the error state adds only the
 *      GDPR message's height.
 * ------------------------------------------------------------------------- */
.get-project-form {
  position: relative;
  height: auto;
  max-height: none;
  padding-bottom: 8px;
}
.get-project-form .vboutEmbedFormRow {
  position: relative;
}
.get-project-form .vboutEmbedFormField .vfb-error {
  position: absolute;
  left: 0;
  bottom: -22px;
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  white-space: nowrap;
}
.get-project-form .vfb-form-error-message {
  position: absolute;
  top: 28px;
  left: 80px;
  right: 80px;
  margin: 0;
  font-size: 14px;
  line-height: 20px;
}
.get-project-form .vboutLPGDPRErrorMessage {
  font-size: 14px;
  line-height: 20px;
}
@media (max-width: 991px) {
  .get-project-form {
    padding-bottom: 25px;
  }
  .get-project-form .vfb-form-error-message {
    left: 25px;
    right: 25px;
    top: 4px;
  }
}

/* ---------------------------------------------------------------------------
 * Homepage "Reviews" heading: match the "Our Portfolio" title above it.
 *
 * The video testimonial block lives inside .software_innovation, whose
 * .section_title override is tuned for the narrow text column beside each
 * video (42px/48px, width 80%, 40px bottom margin). Used as a centred section
 * heading that came out smaller than "Our Portfolio" and crowded against the
 * first video.
 *
 * These selectors are 0,2,0 like the theme's own and this file loads last, so
 * the base .section_title ladder can't be inherited -- it has to be restated.
 * The values below were read back from the live page with
 * CSS.getMatchedStylesForNode on the "Our Portfolio" h2, not from grepping the
 * stylesheet: the 1366px step lives in a grouped selector
 * (`.section_title, .mvp-section .section_title`) that is easy to miss.
 *
 *   default 52px/64px   <= 1366px 41px/49px   <= 992px line-height normal   <= 768px 28px
 *
 * margin-bottom mirrors .selected_works_section's margin-bottom so the
 * whitespace above and below the heading matches at each breakpoint.
 *
 * Only affects the homepage: /testimony renders the block without a title.
 * --------------------------------------------------------------------------- */
.software_innovation .video-testimonials-title {
  font-size: 52px;
  line-height: 64px;
  width: 50%;
  margin-bottom: 135px;
}

@media (max-width: 1366px) {
  .software_innovation .video-testimonials-title {
    font-size: 41px;
    line-height: 49px;
    margin-bottom: 110px;
  }
}

@media (max-width: 1200px) {
  .software_innovation .video-testimonials-title {
    width: 100%;
  }
}

@media (max-width: 992px) {
  .software_innovation .video-testimonials-title {
    line-height: normal;
  }
}

@media (max-width: 768px) {
  .software_innovation .video-testimonials-title {
    font-size: 28px;
    line-height: normal;
  }
}

/* ---------------------------------------------------------------------------
 * AI Services page (/ai-services): fix invisible badge text and
 * overlapping/clipped cards, add hover polish and icon styling.
 *
 * Bootstrap's bare `.badge` ships `color: #fff` with no background set
 * anywhere in the theme (bootstrap.css ~line 4870) -- on this page's light
 * `.service_card`s that renders as invisible white-on-white text (the tag
 * pills, "Step 1"-"Step 6", tech-stack pills, engagement badges). `.ai-badge`
 * gives every one of those a real, on-brand background instead.
 *
 * `.service_card` is theme-wide and hard-coded to `height: 340px;
 * max-width: 340px` (style.css ~line 402), sized for the theme's short
 * icon-only cards elsewhere on the site. This page's cards hold a badge,
 * title, paragraph, a bullet list and a link -- far more content -- so they
 * overflowed that fixed box and visually overlapped the row underneath.
 * `.ai-service-card` is a page-scoped variant with auto height instead, used
 * only where these classes are applied (currently just /ai-services).
 * ------------------------------------------------------------------------- */
.ai-badge {
  background: #656ae5;
  color: #fff;
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  padding: 7px 16px;
  border-radius: 999px;
  margin-bottom: 18px;
}

.ai-badge-outline {
  background: rgba(101, 106, 229, 0.08);
  color: #656ae5;
  border: 1px solid rgba(101, 106, 229, 0.35);
  transition: background 0.25s ease, transform 0.25s ease;
}

.ai-badge-outline:hover {
  background: #656ae5;
  color: #fff;
  transform: translateY(-2px);
}

/* ---------------------------------------------------------------------------
 * `.row.service_block` (the 2-per-row card grid used for step-by-step
 * "process" sections) sets no vertical gutter - Bootstrap's `.row` defaults
 * `--bs-gutter-y` to 0 (bootstrap.css:670), and `service_block` itself only
 * adds a top margin for the whole block (style.css:398), not spacing
 * between individual cards once they wrap onto a second row. Every SIBLING
 * grid on these same pages (`engagement`, `why-us`, `use-cases`) uses
 * Bootstrap's `g-4` utility and doesn't have this problem - `service_block`
 * is the one row style that was never given one.
 *
 * Usually invisible because the theme's own `.service_card` has `border: 0`
 * (style.css:403) - nothing to visibly touch. But `.our_approch_section
 * .ai-service-card` (below) gives the dark "Our Process" variant a real 1px
 * border for contrast on the gradient background, and with zero vertical
 * gutter, two wrapped rows' borders sit flush against each other - reads as
 * a doubled/overlapping line, reported on the AI Services hub's "Our
 * Process" steps.
 *
 * Fixed at the shared class, not per page: `.service_block` is reused
 * identically (same missing gutter) across all 8 AI Services pages, the
 * homepage, about-us, and 7 other service pages - one rule covers all 17
 * usages instead of 17 separate edits, and matches the `g-4` (1.5rem)
 * spacing already used on this page's other card grids for consistency. */
.service_block {
  --bs-gutter-y: 1.5rem;
}

.ai-service-card {
  height: auto;
  max-width: 100%;
  width: 100%;
  margin: 0;
  padding: 40px 32px;
  border-radius: 20px;
  background: #fff;
  box-shadow: 0 4px 24px rgba(19, 26, 35, 0.06);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.ai-service-card:hover {
  transform: translateY(-8px);
  box-shadow: 0 16px 40px rgba(101, 106, 229, 0.18);
}

.ai-service-card--compact {
  padding: 32px 28px;
}

/* Regression fix: renaming `service_card` -> `ai-service-card` (to escape the
 * theme's fixed 340px card height, see the block above) silently broke two
 * compound selectors that were keyed to the OLD class name and never got a
 * replacement: the base paragraph color (style.css:427 `.service_card p`)
 * and, worse, the dark "Our Process" section's white-text override
 * (style.css:1012 `.our_approch_section .service_card p`). Neither matches
 * `.ai-service-card p` at all, so paragraph text fell back to an unstyled
 * default color - invisible on the dark gradient background specifically
 * (Step 1-6 descriptions), and unstyled (wrong color/weight, if technically
 * still readable) everywhere else `.ai-service-card` is used. Restoring both
 * rules verbatim against the new class name.
 * ------------------------------------------------------------------------- */
.ai-service-card p {
  font-family: var(--font-family-inter);
  font-style: normal;
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  color: var(--mirage-4);
  margin: 16px 0 24px;
}

.our_approch_section .ai-service-card p {
  color: var(--white);
  opacity: 0.6;
  word-break: break-word;
}

.ai-service-icon {
  width: 72px;
  height: 72px;
  margin: 0 auto 20px 0;
  transition: transform 0.3s ease;
}

.ai-service-card:hover .ai-service-icon {
  transform: scale(1.08) rotate(-4deg);
}

/* .our_approch_section already resets .card to background:transparent;
   height:auto (style.css ~line 998) for the dark "Our Process" gradient
   section -- give .ai-service-card a border there instead of a white card
   background so the process steps stay readable on the dark gradient. */
.our_approch_section .ai-service-card {
  background: transparent;
  box-shadow: none;
  border: 1px solid rgba(255, 255, 255, 0.14);
}

.our_approch_section .ai-service-card:hover {
  border-color: rgba(101, 106, 229, 0.6);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.25);
  transform: translateY(-6px);
}

.ai-industry-row {
  transition: background 0.25s ease, padding-left 0.25s ease;
  border-radius: 8px;
}

.ai-industry-row:hover {
  background: rgba(101, 106, 229, 0.05);
  padding-left: 12px;
}

@media (max-width: 768px) {
  .ai-service-card {
    padding: 28px 24px;
  }
}

/* ---------------------------------------------------------------------------
 * AI Services page: "Our AI Services" alternating feature-row layout.
 *
 * Replaces the grid-of-cards presentation with a full-width row per service,
 * image alternating left/right (Stripe/Linear-style feature section), so each
 * service gets room to breathe and the illustration reads at a real size.
 * ------------------------------------------------------------------------- */
.ai-feature-rows {
  display: flex;
  flex-direction: column;
  gap: 96px;
}

.ai-feature-row {
  padding: 8px 0;
}

.ai-feature-visual {
  width: 100%;
  height: auto;
  border-radius: 24px;
  box-shadow: 0 20px 60px rgba(101, 106, 229, 0.14);
  transition: transform 0.4s ease, box-shadow 0.4s ease;
}

.ai-feature-row:hover .ai-feature-visual {
  transform: translateY(-6px) scale(1.015);
  box-shadow: 0 28px 70px rgba(101, 106, 229, 0.22);
}

.ai-feature-row .service_title {
  margin-top: 4px;
}

.ai-feature-row .link_arrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}

.ai-feature-row:not(:last-child) {
  padding-bottom: 96px;
  border-bottom: 1px solid rgba(19, 26, 35, 0.08);
}

@media (max-width: 992px) {
  .ai-feature-rows {
    gap: 64px;
  }

  .ai-feature-row:not(:last-child) {
    padding-bottom: 64px;
  }
}

/* ---------------------------------------------------------------------------
 * Every interior page's hero heading: the theme's `.page_title h1` is a
 * fixed 72px (style.css:908), stepping down through five separate
 * breakpoints (70/52/40/40/20/32px - style.css ~3889/4125/5054/5462/
 * 5540/5595) to stay legible. That base size read oversized.
 *
 * This was first fixed scoped to just `.ai-hero` (the /ai-services pages),
 * which then created a NEW inconsistency the other way: AI Services' hero
 * ended up visibly smaller than every other interior page's (about-us,
 * faqs, contact, portfolio, etc.), which still had the unscoped 72px. Every
 * interior page hero should read as the same size and style - so this is
 * now unscoped to plain `.page_title h1`, applying the same fluid clamp()
 * everywhere instead of carving out one page. (The homepage's hero is a
 * separate, deliberately larger pattern - `.mainHeading h1`, not
 * `.page_title h1` - and is untouched by this rule.)
 *
 * That still wasn't the whole fix: `custom-crm-solution`,
 * `custom-software-development`, `fitness-website-and-mobile-application-
 * development`, and `travel-app-development-services` combine BOTH
 * `landingSection` and `landing-title` on their hero, and the theme has a
 * SEPARATE, higher-specificity selector for that exact combo -
 * `.landing-title.landingSection .page_title h1` (style.css ~2974, with its
 * own breakpoint sizes at ~3548/3769/4151/4942: 62/54/52/40px). Higher
 * specificity wins regardless of load order, so on those 4 pages the plain
 * `.page_title h1` rule above was silently losing to that one at every
 * breakpoint except the widest - the actual reason some pages still didn't
 * match after the previous fix. Listed explicitly below so this rule wins
 * there too.
 *
 * Fluid clamp() replaces the breakpoint ladder with one smoothly-scaling
 * rule: ~28px on narrow phones up to ~44px on desktop, instead of jumping
 * straight to 72px.
 * ------------------------------------------------------------------------- */
.page_title h1,
.landing-title.landingSection .page_title h1 {
  font-size: clamp(1.75rem, 1.5rem + 1vw, 2.75rem);
  line-height: 1.15;
}

/* ---------------------------------------------------------------------------
 * AI Services feature-row photos: real stock photos (vs. the hand-built SVG
 * illustrations) rendered edge-to-edge with `width:100%; height:auto` looked
 * oversized - a dense, high-contrast photo at native aspect ratio reads much
 * "bigger" than the light, mostly-negative-space SVGs it replaced, even at a
 * similar box size. `.ai-photo-frame` caps it to a fixed, moderate aspect
 * ratio instead of following the source photo's own proportions.
 *
 * Fix: this used to combine `aspect-ratio: 4/3` with `max-height: 340px`.
 * Those two fight each other - at the main /ai-services rows' wide column
 * (col-lg-6, ~700px) the 340px cap always won over the aspect-ratio, so the
 * box actually rendered at roughly 2:1, not 4:3; at a sub-service page's
 * narrower intro sidebar (col-lg-5, ~450px) the aspect-ratio won instead and
 * it rendered close to the intended 4:3. Same component, two different
 * effective proportions depending on which column it happened to sit in.
 * Dropping the conflicting max-height and using a single aspect-ratio (3:2,
 * a closer match to these photos'/videos' native ~3:2-16:9 range) makes the
 * frame scale proportionally with its column instead, so it renders the same
 * shape everywhere at any width - the actual fix, not just a smaller cap.
 *
 * It also carries the entrance/hover motion (fade-in wow class stays on the
 * column, hover-lift below) while the inner `.ai-photo` gets its own
 * continuous slow "Ken Burns" zoom - a photo has no internal parts to animate
 * the way the SVGs' sparks/gears/dots did, so this is what keeps a photo row
 * visibly alive instead of static once the one-time entrance fade finishes.
 * ------------------------------------------------------------------------- */
/* Fixed 3:2 ratio kept the shape consistent, but at the column's full width
 * (up to ~706px on the wide feature rows) it still rendered as a dominant
 * ~470px-tall block next to noticeably shorter text - reading as oversized
 * relative to the content it's supporting, not just inconsistent in shape.
 * Capping the frame's own max-width (rather than the row/column) lets it sit
 * at a restrained, intentional size - a supporting visual, not the loudest
 * element on the row - while still scaling down further on narrow screens
 * since `width: 100%` still applies below the cap.
 *
 * 420px then read as too small the other way - raised to 560px, which is
 * still clearly short of the ~700px column width that originally read as
 * oversized (so it stays a supporting visual, not full-bleed), but a
 * meaningfully bigger, more confident presence on the row. */
.ai-photo-frame {
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  aspect-ratio: 3 / 2;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 16px 40px rgba(101, 106, 229, 0.14);
  transition: box-shadow 0.4s ease, transform 0.4s ease;
}

.ai-feature-row:hover .ai-photo-frame {
  transform: translateY(-6px);
  box-shadow: 0 28px 70px rgba(101, 106, 229, 0.22);
}

.ai-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Only static photos get the synthetic Ken Burns zoom - a real <video> already
 * has its own motion, so animating it too would just look busy/doubled-up. */
img.ai-photo {
  animation: ai-ken-burns 9s ease-in-out infinite alternate;
}

@keyframes ai-ken-burns {
  from { transform: scale(1) translate(0, 0); }
  to { transform: scale(1.08) translate(-1%, -1%); }
}


/* ---------------------------------------------------------------------------
 * AI sub-service pages: "Capabilities"/"Solutions" bento layout.
 *
 * These sections were a plain uniform grid of text-only cards (badge, title,
 * text, bullet list) - correct but visually flat next to the photo/video rows
 * elsewhere on the page. Rather than source yet more topic images per card,
 * the FIRST card in each of these grids becomes a large "featured" card using
 * the topic's own photo (already downloaded for the hero/intro row) as a
 * background, dark gradient overlay for legible white text. The rest of the
 * cards stay as the existing clean `.ai-service-card` grid below it. This is
 * the asymmetric "bento" pattern (large feature tile + smaller supporting
 * tiles) rather than a uniform grid throughout.
 * ------------------------------------------------------------------------- */
.ai-capability-featured {
  position: relative;
  min-height: 320px;
  border-radius: 20px;
  overflow: hidden;
  background-size: cover;
  background-position: center;
  display: flex;
  align-items: flex-end;
  padding: 32px;
  box-shadow: 0 4px 24px rgba(19, 26, 35, 0.1);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.ai-capability-featured:hover {
  transform: translateY(-6px);
  box-shadow: 0 16px 40px rgba(101, 106, 229, 0.22);
}

.ai-capability-featured::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, rgba(19, 26, 35, 0.92) 0%, rgba(19, 26, 35, 0.55) 55%, rgba(19, 26, 35, 0.15) 100%);
}

.ai-capability-featured-content {
  position: relative;
  z-index: 1;
}

.ai-capability-featured-content .service_title,
.ai-capability-featured-content p {
  color: var(--white);
}

.ai-capability-featured-content p {
  opacity: 0.85;
}

.ai-capability-featured-content ul li {
  color: var(--white);
  opacity: 0.85;
}

@media (max-width: 768px) {
  .ai-capability-featured {
    min-height: 260px;
    padding: 24px;
  }
}

/* ---------------------------------------------------------------------------
 * AI Services hero: ONE deliberate reveal moment on page load, not another
 * scroll-fade to add to the pile. The rest of the page previously had `wow
 * animate__fadeInUp`/`fadeIn` on every section heading, every card, every
 * row, and every badge (22 separate triggers on this page alone) - scattered
 * per-element scroll-fades are exactly the generic, templated-reading motion
 * pattern to avoid; the photo/video rows and the bento capability card
 * already carry real visual interest (actual motion, a featured image) so
 * they don't need a synthetic fade-in wrapped around them too. Those were
 * removed from the rest of the page; this richer blur+rise+fade reveal is
 * reserved for the hero headline alone, where a first-impression moment
 * actually earns the attention.
 * ------------------------------------------------------------------------- */
@keyframes ai-reveal {
  from {
    opacity: 0;
    transform: translateY(28px);
    filter: blur(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
  }
}

.ai-reveal {
  opacity: 0;
  animation: ai-reveal 0.9s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-play-state: paused;
}

.ai-reveal.is-visible {
  animation-play-state: running;
}

.ai-reveal--delay-1.is-visible {
  animation-delay: 0.15s;
}

.ai-reveal--delay-2.is-visible {
  animation-delay: 0.3s;
}

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

/* ---------------------------------------------------------------------------
 * AI Services CTA buttons: match the homepage's "Book Free Consultation"
 * style (white pill, black text, bold 16px) instead of `.free-consultation-
 * btn`'s blue/purple gradient pill at 14px (style.css:1578). Both exist on
 * the site for the same "book a consultation" action - two different looks
 * for one action reads as inconsistent, which is the actual bug.
 *
 * `.free-consultation-btn` is shared by 19 files across the site (not just
 * AI Services), so this is a NEW class applied only on the 8 AI-services
 * pages, rather than restyling the shared one everywhere else too - that
 * wasn't reported as a problem and isn't this task's scope.
 *
 * Unlike the homepage's `.mainHeading .book-btn` (which turns transparent
 * with white text on hover - only legible on a dark hero), these buttons
 * appear on both light sections and a dark CTA band, so the hover here stays
 * a plain background/shadow shift instead of a background-becomes-
 * transparent trick that would go invisible on a light section.
 * ------------------------------------------------------------------------- */
.ai-cta-btn {
  background-color: var(--white);
  color: var(--mirage-2);
  border: 1px solid rgba(19, 26, 35, 0.12);
  font-family: var(--font-family-inter);
  font-weight: 700;
  font-size: 16px;
  padding: 20px 32px;
  transition: background-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
}

.ai-cta-btn:hover {
  background-color: #f4f4f8;
  color: var(--mirage-2);
  box-shadow: 0 10px 24px rgba(19, 26, 35, 0.14);
  transform: translateY(-2px);
}

@media (max-width: 768px) {
  .ai-cta-btn {
    padding: 14px 24px;
    font-size: 15px;
  }
}

/* AI Services hero (main hub + all 7 sub-service pages): a "Book Free
 * Consultation" CTA sits between the h1 and the down_arrow, matching the
 * homepage's hero exactly. `.down_arrow`'s 120px top margin (style.css:321)
 * was tuned for sitting directly under an h1; with a button now in between
 * it left a large, unintentional-looking gap. Icon+label layout also needed
 * its own rule since this button isn't inside `.mainHeading` (the
 * homepage's hero wrapper), so none of that scoped spacing applies here.
 *
 * The h1-to-button gap mirrors the homepage's `.mainHeading .book-btn`
 * margin-top (48px / 35px / 15px at the same breakpoints) rather than an
 * arbitrary smaller value, since the homepage is the explicit spacing
 * reference - even though the homepage's button sits under an extra
 * subtitle paragraph these hero variants don't have, matching the button's
 * own margin keeps the two hero styles reading as the same design.
 *
 * Scoped to `.ai-hero` - a real regression: `.page_title .down_arrow` was
 * left unscoped, so this 40px (tuned to compensate for the button only
 * these 8 pages have) was also overriding the theme's own, much larger
 * default arrow spacing (120px base, plus its own breakpoint values) on
 * every OTHER page sharing this same `page_title`/`down_arrow` hero pattern
 * (about-us, design-services, mobile-development, web-development,
 * dedicated-developer, why-choose-us, the "solution" pages, etc.) - making
 * their arrows sit unnaturally close under the heading, and inconsistent
 * with each other, which is what read as the header sections "not looking
 * the same". Those pages never had a button, so they need no compensation
 * at all - the theme's own spacing there was already correct. */
.ai-hero .page_title .ai-cta-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 48px;
}

.ai-hero .page_title .down_arrow {
  margin-top: 40px;
}

@media (max-width: 1200px) {
  .ai-hero .page_title .ai-cta-btn {
    margin-top: 35px;
  }
}

@media (max-width: 768px) {
  .ai-hero .page_title .ai-cta-btn {
    margin-top: 15px;
  }
}

/* ---------------------------------------------------------------------------
 * AI Services hero (all 8 pages): the down_arrow was overflowing past the
 * bottom edge of the hero's background image at common laptop/tablet widths
 * (roughly 769-1600px) once the CTA button above pushed the hero content
 * taller. The hero image's height comes purely from its own aspect ratio
 * (about-bg.svg is 1920x426, so rendered height = width / 4.507) with no
 * floor between the theme's own ~992px and ~1680px breakpoints - so once
 * h1 + button + arrow (~220px of content) no longer fit under it there, the
 * down_arrow (a light icon meant to sit on the image's dark art) spilled
 * onto the plain page background below it and went effectively invisible -
 * this is the "bottom arrow not showing properly" bug.
 *
 * Fix: give the hero image a min-height (with object-fit: cover to crop
 * rather than stretch/distort) across that width range, mirroring the
 * theme's own pattern already used below 992px for the same image
 * (`.landingDiv .backgroundImg` at style.css:4906 - min-height: 245px).
 * 430px comfortably covers the hero content at every width in the affected
 * range (checked against each of the theme's `.page_title { top }`
 * breakpoints - 115px/65px/18px/50px). Above ~1940px the image's natural
 * height already exceeds 430px, so nothing changes there; below 769px the
 * theme's own floor plus the smaller ≤768px button spacing already keeps
 * the arrow well clear, so this is left to widths where the gap was real.
 *
 * Originally 370px, raised to 430px after the sub-service headings (the 6
 * pages with a full-sentence heroTitle) were given a max-width so they wrap
 * onto 2 lines instead of running edge-to-edge (see the `.ai-hero
 * .page_title h1` rule below) - that made the hero content itself taller
 * (2-line h1 instead of 1), and 370px stopped being enough: verified live,
 * the arrow was spilling ~21px past the image's bottom edge at 1536px
 * width. Any future change to hero content height needs to re-check this
 * floor is still tall enough.
 *
 * Scoped to `.landingDiv > .backgroundImg.bg-none` (direct child, plus the
 * `bg-none` class only the hero background carries) rather than the plain
 * `.backgroundImg` class alone - that class is shared with the swinging
 * trophy illustration on the right (`.illustator_with_trophy img`, same
 * about-illustator.svg used on About/other interior pages), which is a
 * *descendant* of `.landingDiv`, not a direct child. An earlier version of
 * this rule matched both images, growing the illustration bigger than the
 * same graphic on every other interior page - a real regression.
 * ------------------------------------------------------------------------- */
@media (min-width: 769px) {
  .ai-hero .landingDiv > .backgroundImg.bg-none {
    min-height: 430px;
    object-fit: cover;
  }
}

/* ---------------------------------------------------------------------------
 * AI sub-service hero headings: the 6 pages with a full-sentence heroTitle
 * (consulting/generative-ai/chatbots/agents/automation/integration - 51 to
 * 75 characters) had no width limit on `.page_title h1`, so at desktop
 * widths it rendered as ONE line spanning almost the entire viewport
 * (measured ~1910px wide on a 1920px screen for the chatbots page) instead
 * of the short, centered, multi-line heading every other interior page
 * uses - including the homepage, which hand-breaks its h1 with a <br/> into
 * two short, balanced lines rather than letting it run edge to edge.
 *
 * 820px produces the same 2-line, balanced wrap as the homepage for every
 * one of these six (checked against each heading's actual text - e.g.
 * chatbots wraps to "AI chatbot development services your" / "customers
 * actually finish talking to"). The 2 short hero titles that don't use
 * heroTitle (the AI Services hub, AI Development Services) stay well under
 * 820px and are unaffected - still single-line, still centered.
 * ------------------------------------------------------------------------- */
.ai-hero .page_title h1 {
  max-width: 820px;
  margin-left: auto;
  margin-right: auto;
}

/* ---------------------------------------------------------------------------
 * AI hero: subtitle + lede under the h1.
 *
 * The AI Services hub's hero now carries the positioning heading and the intro
 * paragraph that used to open the section below it, so the band has to style
 * and accommodate them:
 *
 *   h1   the page name            "AI Services"
 *   h2   the positioning line     "Build AI Solutions that Move from Idea..."
 *   p    the lede
 *   CTA  Book Free Consultation
 * ------------------------------------------------------------------------- */
.ai-hero .page_title h2 {
  max-width: 900px;
  margin: 0.65rem auto 0;
  color: #f8f9fa;
  font-family: var(--font-family-inter);
  font-weight: 600;
  /* Size and line-height deliberately NOT set here: the client's heading scale
     (heading-scale.css) owns h2 at 30px/26px site-wide, and the hero is not an
     exception to it. Only colour, weight, width and spacing are set here. */
  letter-spacing: -0.01em;
}

.ai-hero .page_title .ai-hero__lede {
  /* Narrower than the h2 on purpose: a measure of roughly 75 characters is
     what keeps a centred paragraph readable. */
  max-width: 760px;
  margin: 1.1rem auto 0;
  color: rgba(248, 249, 250, 0.78);
  font-size: clamp(0.92rem, 0.86rem + 0.2vw, 1.02rem);
  line-height: 1.65;
}

/* The CTA sat directly under the h1 before; it now follows a paragraph and
   needs its own breathing room rather than inheriting the h1's margin. */
.ai-hero .page_title .ai-cta-btn.book-btn {
  margin-top: 1.9rem;
}

@media (max-width: 768.98px) {
  .ai-hero .page_title .ai-hero__lede { margin-top: 0.85rem; }
  .ai-hero .page_title .ai-cta-btn.book-btn { margin-top: 1.4rem; }
}

/* ---------------------------------------------------------------------------
 * ...and let the band grow to fit them.
 *
 * The hero's height came from two fixed numbers: the decorative <img> carries
 * `min-height: 430px` in normal flow, while `.page_title` is absolutely
 * positioned over it at `top: 115px` (style.css:901). Absolute content cannot
 * push its parent, so the band's height never depended on what was inside it.
 * Adding an h2 and a lede overflows it immediately - the last line and the CTA
 * spill past the wave onto the white section below.
 *
 * Rather than guess a taller fixed height (which would only be right at one
 * viewport width, since the h2 and lede wrap differently at every size), the
 * two roles are swapped: the image becomes the backdrop it actually is and is
 * taken out of flow, and the title block goes back into flow and sizes the band
 * itself, with the old `top: 115px` re-expressed as padding so the vertical
 * position is unchanged. The wave is the section's own background image at
 * `background-position: bottom`, so it tracks whatever height results.
 *
 * Gated on `:has(.page_title h2)` so a hero gets the content-driven band
 * exactly when it has content that needs one. The dozens of non-AI pages
 * sharing this `landingSection`/`page_title` pattern keep the fixed height.
 * ------------------------------------------------------------------------- */
.ai-hero:has(.page_title h2) .landingDiv {
  position: relative;
}

.ai-hero:has(.page_title h2) .landingDiv > .backgroundImg.bg-none {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-height: 0;
  object-fit: cover;
  pointer-events: none;
}

.ai-hero:has(.page_title h2) .page_title {
  /* `relative`, not `static`: the backdrop above is positioned, so it paints in
     a later layer than ordinary in-flow content and would cover the heading,
     subtitle and lede outright. `relative` keeps the block in flow, so it still
     sizes the band, while putting it back above the backdrop. */
  position: relative;
  z-index: 1;
  /* The theme's `top: 115px` (style.css:904) placed this block while it was
     absolute. Under `relative` the same declaration becomes a 115px downward
     nudge that stacks on the padding below, opening a void under the nav. */
  top: auto;
  padding-top: 92px;
  /* Clears the wave, which rises into the band at the left and right edges. */
  padding-bottom: 72px;
}

@media (max-width: 768.98px) {
  .ai-hero:has(.page_title h2) .page_title {
    padding-top: 64px;
    padding-bottom: 76px;
  }
}

/* ---------------------------------------------------------------------------
 * Section-to-section gaps: `.your-partner`/`.perfect-technology`/
 * `.our_approch_section`/`.get_in_touch_section` each carry their own large
 * top AND bottom padding (121/121, 49/130, 120/200, 88/72 - style.css:2823,
 * 2839, 986, 521), so wherever two of them sit back to back the padding
 * stacks into 170-250px of empty space - e.g. `.your-partner`'s 121px
 * bottom + `.perfect-technology`'s 49px top = 170px between "What Are AI
 * Services" and "Our AI Services" on the AI Services hub, and worse
 * elsewhere on the same page and its 7 sibling pages (all 8 share this exact
 * section sequence).
 *
 * FIRST ATTEMPT (reverted): pulling the second section up with a negative
 * margin-top sized from the desktop padding values. That broke at
 * intermediate widths, because `.perfect-technology` and `.our_approch_
 * section` both drop to smaller padding at their own theme breakpoint
 * (≤992px: 130/120 top+bottom become 80/80) that doesn't line up with any
 * breakpoint this file used - between ~769-992px the fixed pull exceeded
 * the now-smaller real padding, so the next section's own opaque background
 * (`.our_approch_section` is a dark gradient) got pulled up far enough to
 * paint over the PREVIOUS section's actual content, not just its empty
 * padding - confirmed live: the purple `.ai-badge` tech-stack pills on the
 * Generative AI page were visibly covered by the dark "Our Process" section
 * sliding up over them, and the same mechanism made "Choose the Engagement"
 * overlap the process section above it. A negative margin can never be made
 * safe here without exactly tracking every theme breakpoint for both
 * sides - one missed tier and it silently overlaps again on some page.
 *
 * FIX: set an explicit, small `padding-top` on the second section instead
 * of moving it. This only ever ADDS a fixed, known-positive gap on top of
 * whatever padding-bottom the first section already has at ANY width - it
 * cannot go negative and cannot pull one section's background over
 * another's content, regardless of which theme breakpoint is active or
 * whether it's been fully audited.
 *
 * That first pass (padding-top: 50px, first section's own padding-bottom
 * left untouched) was still leaving 170-212px in places - safe, but read as
 * its own "unwanted space" bug once the overlap was fixed (reported at the
 * "Book a free AI consultation" button -> "Our AI Services", and at the
 * tech-stack badges -> "AI Solutions for Real Business Workflows"). Closed
 * the rest of the gap the same safe way, using `:has()` to also cap the
 * FIRST section's own padding-bottom to a small fixed value - still just
 * two independent absolute positive numbers, never a subtraction from a
 * variable baseline, so this remains impossible to overlap at any
 * breakpoint even though it isn't in this file's `:has()` support floor
 * (Chrome/Edge 105+, Safari 15.4+, Firefox 121+ - safe default for this
 * project). 30px + 40px lands a consistent ~70px break between sections. */
.your-partner + .perfect-technology,
.perfect-technology + .perfect-technology,
.perfect-technology + .our_approch_section,
.our_approch_section + .perfect-technology,
.perfect-technology + .your-partner,
.perfect-technology + .get_in_touch_section {
  padding-top: 30px;
}

.your-partner:has(+ .perfect-technology),
.perfect-technology:has(+ .perfect-technology),
.perfect-technology:has(+ .our_approch_section),
.our_approch_section:has(+ .perfect-technology),
.perfect-technology:has(+ .your-partner),
.perfect-technology:has(+ .get_in_touch_section) {
  padding-bottom: 40px;
}

@media (max-width: 768px) {
  .your-partner + .perfect-technology,
  .perfect-technology + .perfect-technology,
  .perfect-technology + .our_approch_section,
  .our_approch_section + .perfect-technology,
  .perfect-technology + .your-partner,
  .perfect-technology + .get_in_touch_section {
    padding-top: 20px;
  }

  .your-partner:has(+ .perfect-technology),
  .perfect-technology:has(+ .perfect-technology),
  .perfect-technology:has(+ .our_approch_section),
  .our_approch_section:has(+ .perfect-technology),
  .perfect-technology:has(+ .your-partner),
  .perfect-technology:has(+ .get_in_touch_section) {
    padding-bottom: 24px;
  }
}

/* ---------------------------------------------------------------------------
 * AI Services pages: replace whitespace gaps between sections with the
 * pattern measured on aveosoft.com's own Solutions page - every one of its
 * 8 service sections sits flush against the next (0px box gap, verified via
 * getBoundingClientRect on the live site), each with a generous, CONSISTENT
 * 128px top/bottom padding, and the visual break comes entirely from
 * alternating background color rather than empty space. Applied here at
 * 56px (not 128px) to fit our denser card-grid content without making
 * these pages excessively long.
 *
 * Cycles through 4 light colors (white, soft blue-lavender, soft violet,
 * soft sky-blue) rather than a plain 2-way alternation, so consecutive
 * sections read as more distinctly separated - each one closer to the
 * aveosoft.com case-study cards' own approach, which gave each card a
 * different pastel tint (light blue / light teal / light violet) rather
 * than reusing one accent everywhere. All 4 stay within one family (the
 * blue-to-violet range around our own --royal-blue/accent-purple), so the
 * variety reads as deliberate rather than random.
 *
 * This replaces the block above for the 8 AI Services pages only, via
 * higher specificity (`#layout-content:has(> .ai-hero) > section.X` beats
 * `.X + .Y`) - the block above still governs every OTHER page that reuses
 * these same theme classes (mobile-development, custom-crm-solution, etc.),
 * which were not asked to change and already read fine with that approach.
 *
 * Scoped via `#layout-content:has(> .ai-hero)` - `.ai-hero` is a class only
 * these 8 pages' hero section carries - rather than adding a wrapper class
 * to 8 separate page files.
 *
 * `.our_approch_section` and `.get_in_touch_section` set their own
 * background with an inline style (`style={{background: ...}}` in the JSX),
 * which always wins over any CSS rule - so normalizing their padding here
 * doesn't touch their distinct dark backgrounds, which already provide
 * their own strong separation and don't need the alternation below.
 *
 * `:nth-child(An+B of S)` counts position only among siblings matching S,
 * skipping the dark sections without breaking the alternation - Chrome/Edge
 * 111+, Safari 9+, Firefox 113+, the same modern-CSS floor this file
 * already relies on for `:has()`.
 * ------------------------------------------------------------------------- */
#layout-content:has(> .ai-hero) > section.your-partner,
#layout-content:has(> .ai-hero) > section.perfect-technology,
#layout-content:has(> .ai-hero) > section.our_approch_section,
#layout-content:has(> .ai-hero) > section.get_in_touch_section {
  padding-top: 56px;
  padding-bottom: 56px;
}

#layout-content:has(> .ai-hero) > section:nth-child(4n+1 of .your-partner, .perfect-technology) {
  background-color: #ffffff;
}

#layout-content:has(> .ai-hero) > section:nth-child(4n+2 of .your-partner, .perfect-technology) {
  background-color: #eef0fb;
}

#layout-content:has(> .ai-hero) > section:nth-child(4n+3 of .your-partner, .perfect-technology) {
  background-color: #f4eefb;
}

#layout-content:has(> .ai-hero) > section:nth-child(4n of .your-partner, .perfect-technology) {
  background-color: #eaf1fb;
}

@media (max-width: 768px) {
  #layout-content:has(> .ai-hero) > section.your-partner,
  #layout-content:has(> .ai-hero) > section.perfect-technology,
  #layout-content:has(> .ai-hero) > section.our_approch_section,
  #layout-content:has(> .ai-hero) > section.get_in_touch_section {
    padding-top: 32px;
    padding-bottom: 32px;
  }
}

/* =============================================================================
 * PROJECTS FILTER BAR — FOUR TABS ON ONE LINE
 *
 * The bar was measured for three tabs: `style.css:3321` caps the <ul> at
 * 530px while `style.css:3312` gives every pill `padding: 20px 63px`. Three
 * pills come to 514px and just fit; adding AI took the row to 1028px, so it
 * wrapped — and because each `li` is `flex: 1 1 auto`, the lone pill on the
 * second row stretched to the full 514px width of the bar.
 *
 * Two changes, both needed. Lifting the cap alone would not help while the
 * pills carry 126px of horizontal padding each, and trimming the padding alone
 * would still hit the 530px ceiling. So: the bar sizes to its content, and the
 * pills keep generous but not extravagant padding.
 *
 * `white-space: nowrap` stops a label breaking inside its own pill, which is
 * the other way this bar can grow a second line.
 *
 * Done here rather than in style.css because the theme file is overwritten by
 * every `npm run import:october` run.
 * ========================================================================== */
.projects-tabs ul {
  width: fit-content;
  max-width: 100%;
}

.projects-tabs .nav {
  flex-wrap: nowrap;
}

.projects-tabs .nav-link {
  padding: 20px 40px;
  white-space: nowrap;
}

/* Narrow screens cannot hold four pills at desktop padding, and a horizontal
   scrollbar on a filter bar is worse than smaller pills. Shrink rather than
   wrap, so the row stays a row at every width. */
@media (max-width: 767.98px) {
  .projects-tabs .nav-link {
    padding: 14px 20px;
    font-size: 16px;
  }
}

@media (max-width: 479.98px) {
  .projects-tabs .nav-link {
    padding: 12px 14px;
    font-size: 14px;
  }
  .projects-tabs ul {
    padding: 6px;
  }
}

/* ---------------------------------------------------------------------------
 * Blog post author card (components/sections/blog/AuthorCard.tsx): rounded
 * card at the end of a post with photo, name + LinkedIn, title and bio.
 * ------------------------------------------------------------------------- */
.author-card {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  margin: 48px 0 32px;
  padding: 32px 40px;
  border: 1.5px solid #d2d2d5;
  border-radius: 32px;
  background: #fff;
  text-align: left;
}
.author-card__photo {
  flex-shrink: 0;
  width: 68px;
  height: 68px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid #111;
}
.author-card__head { display: flex; align-items: center; gap: 10px; }
.author-card__name { font-weight: 700; font-size: 18px; color: #111; }
.author-card__social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1px solid #d5d5da;
  border-radius: 6px;
  color: #6b6b80;
}
.author-card__social:hover { color: #0a66c2; border-color: #0a66c2; }
.author-card__title {
  margin: 4px 0 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 14px;
  color: #6b6b6b;
}
.author-card__bio { margin: 0; font-size: 16px; line-height: 1.7; color: #3d3d4a; }
@media (max-width: 575.98px) {
  .author-card { flex-direction: column; gap: 16px; padding: 24px; border-radius: 24px; }
}

/* ---------------------------------------------------------------------------
 * AI Services heroes: let the dark band grow with its content.
 *
 * The theme sizes the hero with two fixed numbers: the background <img> has a
 * min-height and sits in flow, while `.page_title` is absolutely positioned
 * over it (`top: 115px`, main.css). Absolute content can't push its parent,
 * so with the global heading scale (public/heading-scale.css) the long
 * sub-service titles ("AI agent development services for tasks that take
 * more than one step") no longer fit: on mobile the last lines fell below
 * the band onto the white section (white on white), and the CTA landed on
 * the wave on desktop and mobile.
 *
 * Fix: image and title block share ONE grid cell, so the band is as tall as
 * whichever is taller. Short content (the hub, AI Development) keeps the
 * image's height and looks exactly as before; long content grows the band.
 * The image stretches to fill (object-fit: cover keeps the art unscaled).
 * The theme's `top` offsets become padding (same values, same breakpoints
 * as main.css), and padding-bottom (the space the short heroes already had
 * below their arrow, so they don't grow) keeps the CTA/arrow clear of the wave,
 * which is the section's own background at `background-position: bottom`.
 * Other children (the trophy illustration) stay absolutely positioned.
 * ------------------------------------------------------------------------- */
.ai-hero .landingDiv {
  display: grid;
}
.ai-hero .landingDiv > .backgroundImg.bg-none,
.ai-hero .landingDiv > .page_title {
  grid-area: 1 / 1;
}
.ai-hero .landingDiv > .backgroundImg.bg-none {
  align-self: stretch;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ai-hero .landingDiv > .page_title {
  position: relative;
  z-index: 1;
  top: auto;
  padding-top: 115px;
  padding-bottom: 62px;
}
@media (max-width: 1366px) { .ai-hero .landingDiv > .page_title { padding-top: 65px; } }
@media (max-width: 1200px) { .ai-hero .landingDiv > .page_title { padding-top: 18px; } }
@media (max-width: 992px)  { .ai-hero .landingDiv > .page_title { padding-top: 50px; padding-bottom: 50px; } }

/* ---------------------------------------------------------------------------
 * Blog article bullets: keep the "•" on the item's first line.
 *
 * The theme draws the bullet as an inline-block `li::before` (main.css,
 * `.blog_info_section ul li::before`, width 1em / margin-left -1em). When a
 * markdown list is "loose" (items separated by blank lines) each item's text
 * is wrapped in a <p>, a block - so the bullet sat alone on a line above the
 * text. Positioning it absolutely at the same spot (-1em, first line) aligns
 * it whatever the item contains; tight lists render exactly as before.
 * ------------------------------------------------------------------------- */
.blog_info_section ul li {
  position: relative;
}
.blog_info_section ul li::before {
  position: absolute;
  left: -1em;
  top: 0;
  margin-left: 0;
}

/* ---------------------------------------------------------------------------
 * Consultation popup: "Hey there!" at 45px.
 *
 * The SEO review asked for this heading to be an H2 (it is, see
 * ConsultationModalTitle) and to render at 45px. heading-scale.css sizes every
 * h2 tag at 30px/26px with `!important`, so matching that specificity is the
 * only way to override it - hence `!important` here too.
 *
 * Scoped to `.consultation-modal`, the popup's own inner wrapper, so the global
 * h2 scale is untouched everywhere else. The popup's `.theme-h1` class is what
 * carries its colour and weight (heading-aliases.css); only the size changes.
 * ------------------------------------------------------------------------- */
.consultation-modal h2 {
  font-size: 45px !important;
  line-height: 1.2 !important;
}

@media (max-width: 575.98px) {
  /* 45px overflows the dialog on a narrow phone; keep the emoji and the
     greeting on one line rather than letting it break mid-word. */
  .consultation-modal h2 {
    font-size: 34px !important;
  }
}

/* ---------------------------------------------------------------------------
 * Smooth in-page scrolling for the consultation CTAs.
 *
 * The "Book Free Consultation" / "Get an AI ... quote" / "Get a free
 * consultation today" buttons used to link to /contacts#contactform, which
 * loaded a different page and dropped the visitor at the top of it. They now
 * point at #project-enquiry, the "Got a Project in Mind?" form in the footer of
 * the page the visitor is already on, and this animates the jump.
 *
 * Set on `html` because that is the scrolling element a fragment navigation
 * acts on; a rule on `body` has no effect. Honoured by the browser for plain
 * `<a href="#...">`, which is why those CTAs are anchors rather than next/link.
 *
 * Respecting prefers-reduced-motion is not optional here: a full-page animated
 * scroll is exactly the kind of motion that triggers vestibular symptoms.
 * ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* The header is `sticky-top`, so it would otherwise cover the top of whatever
   the fragment scrolls to. Applied to the anchor targets rather than globally
   so ordinary layout is untouched. */
#project-enquiry,
#contacts,
#ai-services-intro,
[id^="ai-"][id$="-intro"] {
  scroll-margin-top: 104px;
}

@media (max-width: 991.98px) {
  #project-enquiry,
  #contacts,
  #ai-services-intro,
  [id^="ai-"][id$="-intro"] {
    scroll-margin-top: 88px;
  }
}

/* ===========================================================================
 * BREADCRUMBS  (design samples - see /breadcrumb-samples)
 *
 * One markup shape, five skins. Shared rules first, then one block per
 * variant. Separators are `::before` on every item except the first, so they
 * are decorative only and never read aloud.
 *
 * Colours come from the existing palette: #4fc5eb -> #5d52d9 brand gradient,
 * #1c1e2c body dark, #a4a5aa muted, #f8f9fa light-on-dark.
 * ======================================================================== */
.aveo-crumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.55rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-family-inter, "Inter", sans-serif);
  font-size: 14px;
  line-height: 1.4;
}

.aveo-crumbs li {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}

.aveo-crumbs a {
  text-decoration: none;
  transition: color 0.18s ease, background-color 0.18s ease, border-color 0.18s ease;
}

/* Keyboard focus must stay obvious on both light and dark placements. */
.aveo-crumbs a:focus-visible {
  outline: 2px solid #4fc5eb;
  outline-offset: 3px;
  border-radius: 4px;
}

/* --- A. minimal: chevron separators, for use on the dark hero ------------ */
.aveo-crumbs--minimal ol { justify-content: center; }
.aveo-crumbs--minimal li + li::before {
  content: "›";
  color: rgba(248, 249, 250, 0.45);
  font-size: 16px;
  line-height: 1;
}
.aveo-crumbs--minimal a { color: rgba(248, 249, 250, 0.72); }
.aveo-crumbs--minimal a:hover { color: #fff; }
.aveo-crumbs--minimal .is-current span { color: #fff; font-weight: 600; }

/* --- B. chips: translucent pills, current one on the brand gradient ------ */
.aveo-crumbs--chips ol { justify-content: center; gap: 0.5rem; }
.aveo-crumbs--chips li + li::before {
  content: "";
  width: 14px;
  height: 1px;
  background: rgba(248, 249, 250, 0.3);
}
.aveo-crumbs--chips a,
.aveo-crumbs--chips .is-current span {
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 13px;
  letter-spacing: 0.01em;
}
.aveo-crumbs--chips a {
  color: rgba(248, 249, 250, 0.8);
  background: rgba(248, 249, 250, 0.08);
  border: 1px solid rgba(248, 249, 250, 0.16);
}
.aveo-crumbs--chips a:hover {
  color: #fff;
  background: rgba(248, 249, 250, 0.16);
  border-color: rgba(248, 249, 250, 0.3);
}
.aveo-crumbs--chips .is-current span {
  color: #fff;
  font-weight: 600;
  background: linear-gradient(255.4deg, #4fc5eb 0%, #5d52d9 100%);
  border: 1px solid transparent;
}

/* --- C. bar: a light strip between the header and the hero --------------- */
.aveo-crumbs--bar {
  background: #f6f7f9;
  border-bottom: 1px solid #e6e8ec;
}
.aveo-crumbs--bar ol {
  max-width: 1320px;
  margin: 0 auto;
  padding: 13px 24px;
}
.aveo-crumbs--bar li + li::before {
  content: "/";
  color: #b7b9c0;
}
.aveo-crumbs--bar a { color: #5a5c69; }
.aveo-crumbs--bar a:hover { color: #5d52d9; }
.aveo-crumbs--bar .is-current span { color: #1c1e2c; font-weight: 600; }

/* --- D. underline: hero-placed, gradient rule under the current page ----- */
.aveo-crumbs--underline ol { justify-content: center; }
.aveo-crumbs--underline li + li::before {
  content: "›";
  color: rgba(248, 249, 250, 0.4);
  font-size: 16px;
  line-height: 1;
}
.aveo-crumbs--underline a {
  color: rgba(248, 249, 250, 0.72);
  padding-bottom: 3px;
  border-bottom: 2px solid transparent;
}
.aveo-crumbs--underline a:hover {
  color: #fff;
  border-bottom-color: rgba(79, 197, 235, 0.65);
}
.aveo-crumbs--underline .is-current span {
  color: #fff;
  font-weight: 600;
  padding-bottom: 3px;
  border-bottom: 2px solid transparent;
  border-image: linear-gradient(255.4deg, #4fc5eb 0%, #5d52d9 100%) 1;
}

/* --- E. compact: muted trail, current page in brand cyan ----------------- */
.aveo-crumbs--compact ol { justify-content: center; gap: 0.35rem 0.5rem; font-size: 13px; }
.aveo-crumbs--compact li + li::before {
  content: "/";
  color: rgba(164, 165, 170, 0.55);
}
.aveo-crumbs--compact a {
  color: #a4a5aa;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.aveo-crumbs--compact a:hover { color: #f8f9fa; }
.aveo-crumbs--compact .is-current span {
  color: #51c0ea;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
}

/* Hero placement: sit the trail above the H1 with room to breathe. */
.ai-hero .page_title .aveo-crumbs,
.page_title .aveo-crumbs { margin-bottom: 1.1rem; }

@media (max-width: 575.98px) {
  .aveo-crumbs ol { font-size: 13px; }
  .aveo-crumbs--bar ol { padding: 11px 16px; }
}

/* --- /breadcrumb-samples review page only (delete with that route) ------- */
.sample-page { padding: 56px 0 96px; }
.sample-intro { max-width: 820px; color: #4a4c58; margin: 18px 0 44px; }
.sample-intro code { background: #f0f1f4; padding: 1px 5px; border-radius: 4px; font-size: 0.9em; }
.sample-block { margin-bottom: 64px; padding-top: 28px; border-top: 1px solid #e6e8ec; }
.sample-block__name { margin-bottom: 6px; }
.sample-block__note { color: #5a5c69; max-width: 760px; margin-bottom: 20px; }
.sample-hero {
  background: #131a23;
  background-image: linear-gradient(140deg, #131a23 0%, #1c2433 100%);
  border-radius: 14px;
  padding: 44px 28px 40px;
  text-align: center;
}
.sample-hero--flush { border-radius: 0; }
.sample-hero__title { color: #f8f9fa !important; margin: 0; }
.sample-hero__lede { color: rgba(248, 249, 250, 0.72); margin: 12px auto 0; max-width: 560px; font-size: 15px; }
.sample-row { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px; }
.sample-row .sample-hero { padding: 30px 20px 26px; }
.sample-row .sample-hero__lede { display: none; }
.sample-tag {
  display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: #a4a5aa; margin-bottom: 8px;
}
@media (max-width: 767.98px) { .sample-row { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------------------
 * Breadcrumb PLACEMENT modifiers (style stays `--minimal`).
 *
 * Placement is kept separate from the skin so the approved style can be moved
 * without touching its colours. `--on-light` flips the palette for the two
 * placements that sit on a white/grey background.
 * ------------------------------------------------------------------------- */

/* Palette flip for light backgrounds. */
.aveo-crumbs--on-light li + li::before { color: #b7b9c0; }
.aveo-crumbs--on-light a { color: #5a5c69; }
.aveo-crumbs--on-light a:hover { color: #5d52d9; }
.aveo-crumbs--on-light .is-current span { color: #1c1e2c; }

/* P1 - top-left inside the hero, above the title block. */
.aveo-crumbs--at-hero-left ol {
  justify-content: flex-start;
  max-width: 1320px;
  margin: 0 auto;
  padding: 0 24px;
}

/* P2 - light strip between the header and the hero. */
.aveo-crumbs--at-bar-light {
  background: #f6f7f9;
  border-bottom: 1px solid #e6e8ec;
}
.aveo-crumbs--at-bar-light ol {
  justify-content: flex-start;
  max-width: 1320px;
  margin: 0 auto;
  padding: 12px 24px;
}

/* P3 - dark strip across the top of the hero, hairline under it. */
.aveo-crumbs--at-bar-dark {
  /* `.landingDiv` is a single-cell grid (1 row / 1 col) with the title block and the
     absolutely positioned backdrop all stacked in cell 1/1. Join that cell and pin to
     its top edge, so the strip runs the full hero width over the dark art instead of
     creating a second grid row underneath the title. */
  grid-area: 1 / 1;
  align-self: start;
  position: relative;
  z-index: 2;
  width: 100%;
}
.aveo-crumbs--at-bar-dark ol {
  justify-content: flex-start;
  max-width: 1320px;
  /* Centres the 1320px track in the viewport so the trail starts on the same
     gutter as the page content below it, rather than flush to the window edge. */
  margin: 0 auto;
  padding: 18px 24px 14px;
}

/* The title block keeps its own 92px of clearance under the header; with the strip
   occupying the top of the same cell, start the title below it instead. */
.ai-hero:has(.aveo-crumbs--at-bar-dark) .page_title {
  padding-top: 132px;
}
@media (max-width: 768.98px) {
  .ai-hero:has(.aveo-crumbs--at-bar-dark) .page_title { padding-top: 112px; }
}

/* Three hero shapes carry this strip, and they lay out differently:
 *
 *   .ai-hero          .landingDiv is a single-cell grid, the backdrop is absolute and
 *                     .page_title is in flow  -> join the cell (rules above).
 *   .landingDiv.blog-bg   block flow, the dark art is the div's own background and the
 *                     title is in flow        -> the strip just flows above it, no rule.
 *   everything else   block flow, but the art is an in-flow <img> ~424px tall and
 *                     .page_title is absolute -> an in-flow strip lands BELOW the art,
 *                     out in the wave. Pin it to the top of the band instead.
 */
.landingSection:not(.ai-hero) .landingDiv:not(.blog-bg) > .aveo-crumbs--at-bar-dark {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  width: auto;
}

/* Those same heroes put `.page_title` at `top: 115px` on desktop (clear of the
   strip) but `top: 50px` further down, which is exactly the strip's height - the
   title lands flush against it and wraps into it on a narrow phone. Push it clear.
   `.page_title` is absolutely positioned, so a margin shifts it. */
@media (max-width: 991.98px) {
  .landingSection:not(.ai-hero) .landingDiv:not(.blog-bg) > .aveo-crumbs--at-bar-dark ~ .page_title {
    margin-top: 42px;
  }
}

/* P4 - first line of the content section below the hero. */
.aveo-crumbs--at-below ol {
  justify-content: flex-start;
  max-width: 1320px;
  margin: 0 auto;
  padding: 26px 24px 0;
}

@media (max-width: 575.98px) {
  .aveo-crumbs--at-hero-left ol,
  .aveo-crumbs--at-bar-light ol,
  .aveo-crumbs--at-bar-dark ol,
  .aveo-crumbs--at-below ol { padding-left: 16px; padding-right: 16px; }
}

/* --- placement mock chrome (/breadcrumb-samples only) ------------------- */
.pos-mock { border: 1px solid #e6e8ec; border-radius: 12px; overflow: hidden; }
.pos-mock__header {
  display: flex; align-items: center; justify-content: space-between;
  background: #11161f; color: #f8f9fa; padding: 14px 24px;
}
.pos-mock__logo { font-weight: 800; letter-spacing: 0.08em; font-size: 13px; }
.pos-mock__nav { font-size: 12px; color: rgba(248, 249, 250, 0.6); }
.pos-mock__hero { background: linear-gradient(140deg, #131a23 0%, #1c2433 100%); }
.pos-mock__herobody { padding: 34px 24px 40px; text-align: center; }
.pos-mock__title { color: #f8f9fa !important; margin: 0; }
.pos-mock__sub { color: rgba(248, 249, 250, 0.82); margin: 10px auto 0; max-width: 520px; font-size: 15px; }
.pos-mock__cta {
  display: inline-block; margin-top: 18px; padding: 9px 22px; border-radius: 999px;
  background: #fff; color: #1c1e2c; font-size: 13px; font-weight: 600;
}
.pos-mock__content { background: #fff; padding: 26px 24px 30px; color: #4a4c58; }
.pos-mock__content strong { display: block; color: #1c1e2c; margin-bottom: 6px; font-size: 17px; }
.pos-mock__content p { margin: 0; font-size: 14px; }
.pos-pad-top { padding-top: 22px; }
/* in P5 the trail sits inside the centred hero body */
.pos-mock__herobody > .aveo-crumbs { margin-bottom: 14px; }
