/* ==========================================================================
   GEOTECH — Shopify Store Rescue
   Campaign layer over the cloned base theme.

   The theme's own CSS does the layout, type scale, grid and section rhythm.
   This file only:
     1. remaps the theme's accent token (red #fc3637 -> GEOTECH skyblue),
     2. supplies the handful of tokens/keyframes the theme references but
        never ships,
     3. styles the things the funnel adds: countdown, VSL, offer card and
        lead form, plus the mobile sticky CTA.
   Loaded last, so it wins on equal specificity.
   ========================================================================== */

:root {
  /* GEOTECH brand tokens, taken from the geotechengine.com Tailwind theme */
  --gt-navy: #031942;        /* navy.DEFAULT / 950 */
  --gt-ink: #020c1f;         /* darkest surface */
  --gt-ink-soft: #0a1c3d;    /* raised dark surface */
  --gt-sky: #0ea5e9;         /* skyblue accent */
  --gt-sky-light: #56c7f8;
  --gt-on-navy-muted: #bde5f4;
  --gt-on-navy-subtle: #92c4dd;
  --gt-steel-100: #f1f4f7;
  --gt-steel-200: #dfe6ec;
  --gt-steel-600: #586979;

  /* ---- accent remap: base theme red -> GEOTECH skyblue --------------------- */
  --primary: var(--gt-sky);
  --primary-2: var(--gt-sky);
  --primary_hover: var(--gt-sky);

  /* Skyblue carries navy text, not white: #031942 on #0EA5E9 is 5.5:1,
     white on #0EA5E9 is only 2.9:1. */
  --cta-button: var(--gt-sky);
  --cta-text: var(--gt-navy);
  --cta-button-hover: rgba(0, 0, 0, 0);
  --cta-text-hover: var(--gt-sky);

  --bg-cart-count: var(--gt-sky);
  --background-service-hover: var(--gt-sky);

  /* Skyblue type on white is only 3:1, so eyebrows stay navy and take a
     skyblue highlight instead (see .sub-heading .subbg-text below). */
  --sub-heading-color: var(--gt-navy);

  /* pull the theme's neutral body/heading colours into the brand family */
  --heading-color: 3, 25, 66;
  --root-heading-color: 3, 25, 66;
  --color-body: 88, 105, 121;
  --root-text-color: 88, 105, 121;

  /* tokens the theme's component CSS reads but never sets */
  --color-foreground: 3, 25, 66;
  --small-font-size: 16px;
  --font-heading-scale: 1;
  --text-boxes-border-width: 1px;
  --text-boxes-border-opacity: 0.12;

  /* The theme points these decorative marks at a path that only resolves on
     the live Shopify CDN, so the mirror 404s on them. Inlined here, in GEOTECH skyblue. */
  --icon-sub-svg-url: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><path d='M7.2 0h1.6v16H7.2z' fill='%230EA5E9'/><path d='M16 7.2v1.6H0V7.2z' fill='%230EA5E9'/><path d='m13.11 1.8 1.09 1.09L2.89 14.2 1.8 13.11z' fill='%230EA5E9'/><path d='m14.2 13.11-1.09 1.09L1.8 2.89 2.89 1.8z' fill='%230EA5E9'/></svg>");
  --icon-sub-svg-url-2: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><path d='M7.2 0h1.6v16H7.2z' fill='%230EA5E9'/><path d='M16 7.2v1.6H0V7.2z' fill='%230EA5E9'/><path d='m13.11 1.8 1.09 1.09L2.89 14.2 1.8 13.11z' fill='%230EA5E9'/><path d='m14.2 13.11-1.09 1.09L1.8 2.89 2.89 1.8z' fill='%230EA5E9'/></svg>");
  --icon-sub-svg-url-3: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'><path d='M7.2 0h1.6v16H7.2z' fill='%230EA5E9'/><path d='M16 7.2v1.6H0V7.2z' fill='%230EA5E9'/><path d='m13.11 1.8 1.09 1.09L2.89 14.2 1.8 13.11z' fill='%230EA5E9'/><path d='m14.2 13.11-1.09 1.09L1.8 2.89 2.89 1.8z' fill='%230EA5E9'/></svg>");

  --gt-stickybar-h: 0px;
}

@media (max-width: 991px) {
  /* reserve the sticky CTA's height so it never covers the footer.
     Measured at 390: the bar renders 105px (meta line + full-width button
     + its own safe-area pad), so 92px left the last footer line under it. */
  :root { --gt-stickybar-h: 108px; }
}

body.gt-page { padding-bottom: var(--gt-stickybar-h); overflow-x: hidden; }

/* The theme names this keyframe but ships it in no stylesheet, so the
   scroll-text strip would sit still without it. */
/* Scroll reveals: AOS's stylesheet ships inline with the page and hides every
   [data-aos] element until it gets .aos-animate. geotech.js adds .gt-aos to
   <html> the moment it takes over, so if that script never runs the content
   stays visible instead of the page rendering blank. */
html:not(.gt-aos) [data-aos] {
  opacity: 1 !important;
  transform: none !important;
}
@media (prefers-reduced-motion: reduce) {
  [data-aos] { transition: none !important; }
}

@keyframes loop-anim-right { from { transform: translateX(0); } to { transform: translateX(-100%); } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .anim-loop-right, .anim-loop-left, .ani-scaleLoop { animation: none !important; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

html { scroll-behavior: smooth; }
[id] { scroll-margin-top: 96px; }

/* Visible focus everywhere keyboard-reachable — the theme ships
   .no-focus-outline on <body>. */
body.no-focus-outline a:focus-visible,
body.no-focus-outline button:focus-visible,
body.no-focus-outline summary:focus-visible,
body.no-focus-outline input:focus-visible,
body.no-focus-outline select:focus-visible,
body.no-focus-outline textarea:focus-visible {
  outline: 3px solid var(--gt-sky) !important;
  outline-offset: 3px;
}

.gt-skip {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  background: var(--gt-sky); color: var(--gt-navy); font-weight: 700;
  padding: 12px 20px; border-radius: 0 0 8px 0;
}
.gt-skip:focus { left: 0; }

/* Eyebrows: navy text on a skyblue highlight instead of the base theme's red text. */
.sub-heading .subbg-text {
  background: var(--gt-sky);
  color: var(--gt-navy);
  padding: 5px 13px;
  border-radius: 999px;
  display: inline-block;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Outline buttons: skyblue borders on white fail contrast, so they run navy
   and fill with skyblue on hover. */
.btn-outline-red { border-color: var(--gt-navy); color: var(--gt-navy); }
/* the same outline button on a dark band */
/* The base theme paints this band pure #000. The hero, the offer band and the footer
   are all GEOTECH ink (#020c1f), so pure black leaves a visible seam where the
   hero meets it. */
.gt-on-dark { background-color: var(--gt-ink) !important; }
.gt-on-dark .btn-outline-red { border-color: rgba(255, 255, 255, 0.45); color: #fff; }
.gt-on-dark .btn-outline-red:hover { background-color: var(--gt-sky); border-color: var(--gt-sky); color: var(--gt-navy); }
.btn-outline-red:hover { background-color: var(--gt-sky); border-color: var(--gt-sky); color: var(--gt-navy); }
.btn-base, .style-btn-base { color: var(--gt-navy); }
.btn-base:hover { border-color: var(--gt-sky); color: var(--gt-sky); }
.gt-btn-pill { min-height: var(--button-medium-height); }

/* ==========================================================================
   1. Urgency bar
   ========================================================================== */
.gt-topbar { background: var(--gt-ink); border-bottom: 1px solid rgba(255, 255, 255, 0.14); position: relative; z-index: 30; }
.gt-topbar__inner {
  min-height: 44px;
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 4px 18px; padding: 9px 0; text-align: center;
}
.gt-topbar__label, .gt-topbar__clock {
  margin: 0; font-size: 13px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: #fff;
  font-family: var(--body-font-family);
}
.gt-topbar__label b { color: var(--gt-sky-light); }
.gt-topbar__clock { color: var(--gt-sky-light); letter-spacing: 0.06em; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   2. Header — the base theme's header, made solid and stripped to logo + CTA
   ========================================================================== */
.gt-header.header {
  position: sticky; top: 0; z-index: 25;
  background: var(--gt-ink);
  padding: 14px 0;
}
.gt-header__wrapper { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.gt-header__spacer { display: none; }
@media (min-width: 992px) {
  /* The base theme centres the mark and keeps the one action on the right */
  .gt-header__spacer { display: block; flex: 1 1 0; }
  .gt-header .header-logo { flex: 0 0 auto; }
  .gt-header .header-contact { flex: 1 1 0; display: flex; justify-content: flex-end; }
}
.gt-header .header__logo-image { width: 172px; height: auto; display: block; }
.gt-header .btn-outline-white { padding: 0 24px; white-space: nowrap; }
@media (max-width: 480px) {
  .gt-header .header__logo-image { width: 132px; }
  .gt-header .btn-outline-white { padding: 0 16px; font-size: 14px; }
}

/* ==========================================================================
   3. Hero
   ========================================================================== */
.image-banner-2 { padding: 120px 0 60px !important; }
@media (max-width: 1199px) { .image-banner-2 { padding: 120px 0 60px !important; } }
@media (max-width: 767px) { .image-banner-2 { padding: 120px 0 60px !important; } }

.image-banner-2 .banner-content__heading {
  font-size: clamp(30px, 6.1vw, 88px) !important;
  line-height: 1.02 !important;
  letter-spacing: -0.035em !important;
  text-wrap: balance;
}
.image-banner-2 .banner__content-top > .banner-content__heading:first-of-type { color: rgba(255, 255, 255, 0.58); }
.image-banner-2 .banner__content-item p { margin: 0; }
@media (min-width: 1200px) { .image-banner-2 > .container-fluid { padding-left: 15px; padding-right: 15px; } }

/* The base theme's floating render sits behind the copy, never across it. */
/* The base theme's render is position:absolute with z-index:auto and opacity:1, and
   every piece of hero text is static — so the absolutely positioned render
   paints OVER the type and the headline runs behind it. That occlusion is the
   whole effect. Forcing the render to z-index:0 and the text to z-index:2
   inverts it and the object sits flatly behind the words instead. Left to the
   theme's own stacking, exactly as the base theme ships it. It reaches neither the
   action column (x>=1058) nor the service list (x<=190), so it only ever
   crosses the headline. */
@media (min-width: 1200px) {
  .image-banner-2 .banner-content__image-child { top: 300px !important; right: 34% !important; max-width: 360px; }
}

.gt-hero-actions { margin-top: 26px; }

.gt-countdown { display: flex; flex-wrap: wrap; align-items: stretch; gap: 8px; margin: 0 0 16px; }
.gt-countdown__unit {
  min-width: 62px; padding: 8px 8px 9px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 12px; text-align: center;
  background: rgba(255, 255, 255, 0.05);
}
.gt-countdown__unit b {
  display: block; font-family: var(--hd-font-family);
  font-size: 24px; font-weight: 700; line-height: 1; color: #fff;
  font-variant-numeric: tabular-nums;
}
.gt-countdown__unit i {
  display: block; font-style: normal; font-size: 10px; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6); margin-top: 5px;
}
.gt-countdown__tz {
  align-self: center; max-width: 118px;
  font-size: 12px; font-weight: 600; line-height: 1.3;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--gt-sky-light);
}
.gt-hero-urgency { margin: 0 0 18px; font-size: 16px; font-weight: 600; color: #fff; }
.gt-hero-proof { margin: 16px 0 0; font-size: 16px; font-weight: 600; color: rgba(255, 255, 255, 0.72); }
.image-banner-2 .banner-button .button { width: auto; }

/* The bundled Swiper CSS targets `.swiper`, but the mirrored markup still uses
   Swiper 6's `.swiper-container`, so the slide track is never clipped and drags
   the whole document wider than the viewport. */
.ap-swiper, .swiper-container { overflow: hidden; }
/* The carousel section ships an id-scoped `overflow: visible` so its slides can
   bleed past the container. That bleed widens the document itself, so it is
   clipped here — !important is the only way past an id selector. */
.team-carousel, .team-carousel .swiper-container { overflow: hidden !important; }

/* ==========================================================================
   Marquee
   ========================================================================== */
.scroling-section { overflow: hidden; }
.scroling-section .text-scroll { display: flex; width: max-content; }
.scroling-section .textscroll-item { display: flex; }
.scroling-section .image-content__image { width: 34px; height: 34px; }

/* ==========================================================================
   4. Pain cards
   ========================================================================== */
.gt-pain-close {
  margin: 44px 0 0;
  font-family: var(--hd-font-family);
  font-size: clamp(22px, 4vw, 38px);
  font-weight: 600; line-height: 1.2; letter-spacing: -0.02em;
  color: rgb(var(--heading-color));
  border-left: 4px solid var(--gt-sky);
  padding-left: 20px;
}

/* ==========================================================================
   5. VSL
   ========================================================================== */
.gt-vsl { padding: 90px 0; }
@media (max-width: 767px) { .gt-vsl { padding: 56px 0; } }
.gt-vsl__frame {
  position: relative; overflow: hidden;
  border-radius: var(--block-border-radius);
  background: var(--gt-ink); aspect-ratio: 16 / 9;
  max-width: 980px; margin: 0 auto;
}
.gt-vsl__frame > iframe, .gt-vsl__frame > video {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block;
}
.gt-vsl__poster {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  padding: 0; border: 0; background: var(--gt-ink); cursor: pointer;
}
.gt-vsl__poster img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.gt-vsl__play {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 86px; height: 86px; border-radius: 999px;
  background: var(--gt-sky); color: var(--gt-navy);
  box-shadow: 0 12px 44px rgba(0, 0, 0, 0.45);
  transition: transform 0.25s ease;
}
.gt-vsl__poster:hover .gt-vsl__play { transform: scale(1.06); }
/* The runtime chip predates the designed poster and now duplicates it - the art
   carries "A 60-75 second walkthrough from the founder." on the same corner, so
   the chip only restated it one line lower and out of alignment. The markup
   comes from the auto-generated section, so it is hidden here rather than cut.
   The play button keeps its own aria-label, so nothing is lost to screen
   readers. Restore this if the poster art ever loses that line. */
.gt-vsl__runtime { display: none; }
.gt-vsl__fallback {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  background: linear-gradient(180deg, rgba(2, 12, 31, 0), rgba(2, 12, 31, 0.94) 42%);
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  gap: 8px; text-align: center; padding: 70px 24px 26px; color: #fff;
}
.gt-vsl__fallback strong { font-family: var(--hd-font-family); font-size: 22px; font-weight: 600; }
.gt-vsl__fallback p { margin: 0; font-size: 16px; line-height: 1.5; color: rgba(255, 255, 255, 0.78); max-width: 46ch; }
.gt-vsl__fallback code { color: var(--gt-sky-light); }
.gt-vsl__transcript { max-width: 980px; margin: 20px auto 0; }
.gt-vsl__transcript > summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 0; font-size: 16px; font-weight: 700; color: rgb(var(--heading-color));
}
.gt-vsl__transcript > summary::-webkit-details-marker { display: none; }
.gt-vsl__transcript > summary::after { content: "+"; font-size: 20px; line-height: 1; }
.gt-vsl__transcript[open] > summary::after { content: "–"; }
.gt-vsl__transcript ol { margin: 6px 0 0; padding-left: 22px; font-size: 16px; line-height: 1.65; }

/* ==========================================================================
   6. Proof cards become links
   ========================================================================== */
/* The theme's 540px floor made the card box 1.278 at 1440 while the shots are
   1.704, so cover() dropped a quarter of the width whatever the anchor: a
   centred crop cut ARC's "IT'S ARC." headline off at the I, and a left anchor
   shoved Lacomus's centred hero into the right edge. Matching the box to the
   shots' own ratio removes the crop entirely, so both storefronts show whole
   and centred. Cards land ~405px tall at 1440 instead of 540. */
.gt-proof-link .banner-list-image {
  min-height: 0 !important;
  height: auto;
  aspect-ratio: 1440 / 845;
  object-position: center;
}
.gt-proof-link { display: block; color: inherit; text-decoration: none; }
.gt-proof-link:focus-visible { outline: 3px solid var(--gt-sky); outline-offset: 4px; }
.gt-proof-link .heading-center span { transition: color 0.25s ease; }
.gt-proof-link:hover .heading-center span { color: var(--gt-sky-light); }

/* The eyebrow answers hover the same way the title does, in colour rather than
   as a chip - the pill read as a button on a card that is already one link. */
.gt-proof-link .sub-heading span.text-small { transition: color 0.25s ease; }
.gt-proof-link:hover .sub-heading span.text-small { color: var(--gt-sky-light); }

/* The base theme's counter row, reused for the three-step process */
.gt-steps .counter-number { color: var(--gt-sky) !important; }
.gt-steps .counter-label { display: none; }

/* ==========================================================================
   7. Offer card
   ========================================================================== */
/* The offer runs on the base theme's pricing card, borrowed with its own CSS from
   pages/pricing-plan-style-02. Only the things that differ are set here: the
   band is dark so the white card carries the offer, and the base theme's three-card
   grid holds one card, because there is one price and inventing two more
   tiers would mean inventing prices. */
.gt-offer { padding: 100px 0; }   /* the plate is declared with the section */
@media (max-width: 767px) { .gt-offer { padding: 56px 0; } }
.gt-offer .section__header .heading { color: #fff; }
/* One card at the base theme's card width would leave half the band empty, so the
   band reads as two columns - the heading and the small print on the left,
   the card on the right - the way the base theme's own pricing header sits beside
   its controls. The base theme's grid is space-between with flex:1 cards and ships
   after this file, so these have to outrank it on specificity, not order. */
.gt-offer.pricing-section .pricing-grid { justify-content: center; }
.gt-offer.pricing-section .pricing-card-wp { width: 100%; max-width: 407px; flex: 0 0 auto; }  /* the base theme's card is 407px */
@media (min-width: 992px) {
  /* Grid rather than flex so the small print can follow the card in source
     order - on a phone it would otherwise sit between the heading and the
     offer - while still sitting under the heading on a wide screen. */
  .gt-offer__layout {
    display: grid; grid-template-columns: 1fr 460px; column-gap: 80px; align-items: center;
  }
  .gt-offer__intro { grid-column: 1; grid-row: 1; min-width: 0; }
  .gt-offer__layout .pricing-grid { grid-column: 2; grid-row: 1 / span 2; }
  .gt-offer__scope { grid-column: 1; grid-row: 2; }
  .gt-offer__intro .section__header { margin-bottom: 0 !important; }
}
.gt-offer__bonus { border-top: 1px solid #e6e6e6; margin-top: 22px; padding-top: 18px; }

/* The base theme hard-codes its pricing button to #000 and inverts it to white on
   hover. The page has one CTA style, so this takes the brand pill and the
   same inversion - skyblue with navy text (5.5:1), inverting to navy on
   white. Both outrank the base theme's rule on specificity, which matters because
   its CSS ships inline after this file. */
.gt-offer .plan-purchase-button {
  background-color: var(--gt-sky);
  color: var(--gt-navy);
  border: 1px solid var(--gt-sky);
  /* The base theme's hover roll wraps the label in an inline-block, which sits on the
     text baseline and leaves descender space under it - 1px above the label
     and 19px below, and 18px of height the button should not have. Centring
     it as a flex item removes both. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.gt-offer .plan-purchase-button:hover {
  background-color: #fff;
  color: var(--gt-navy);
  border: 1px solid var(--gt-navy);
}
.gt-offer__label {
  font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: #6b7280; margin: 0 0 12px;
}
.gt-offer__scope {
  max-width: 54ch; margin: 26px 0 0; padding-left: 16px;
  border-left: 2px solid rgba(255, 255, 255, 0.28);
  font-size: 14px; line-height: 1.6; color: rgba(255, 255, 255, 0.75);
}

/* ==========================================================================
   8. FAQ
   ========================================================================== */
.gt-faq { padding: 90px 0; }
@media (max-width: 767px) { .gt-faq { padding: 56px 0; } }
.gt-faq__list { max-width: 900px; }
.gt-faq__row { margin: 0; border: 0; border-top: 1px solid rgba(0, 0, 0, 0.14); }
.gt-faq__row:last-child { border-bottom: 1px solid rgba(0, 0, 0, 0.14); }
.gt-faq__row summary {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 24px 2px; cursor: pointer; list-style: none; line-height: 1.35;
}
.gt-faq__row summary::-webkit-details-marker { display: none; }
.gt-faq__row .accordion__title { margin: 0; }
.gt-faq__icon {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 999px;
  background: var(--gt-sky); color: var(--gt-navy);
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.25s ease;
}
.gt-faq__row details[open] .gt-faq__icon { transform: rotate(45deg); }
.gt-faq__row .accordion__content { height: auto; overflow: visible; padding: 0 2px 26px; }
.gt-faq__row .accordion__content p { margin: 0; font-size: 16px; line-height: 1.65; max-width: 70ch; }

/* ==========================================================================
   9. Lead form
   ========================================================================== */
/* The section reuses the base theme's contact-form-section: its dark render plate,
   its .contact-form pill inputs and its three-across field row. Only the parts
   The base theme has no equivalent for - per-field errors, the submit state and the
   success panel - are styled here, to sit on that dark plate. */
.gt-form-wrap { width: 100%; }
.gt-form-wrap form { width: 100%; }
.gt-contact-form .contact-form .field__input { min-height: 60px; font-size: 16px; }
.gt-contact-form .contact-form .field__input::placeholder { opacity: 1; }
.gt-contact-form .contact-form textarea.field__input { min-height: 150px; resize: vertical; }
.gt-contact-form .contact-form select.field__input {
  padding-right: 54px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23ffffff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 26px center; background-size: 14px 9px;
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
}
.gt-contact-form .contact-form select.field__input option { color: var(--gt-navy); }
.gt-contact-form .contact-form .field__input:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.gt-contact-form .contact-form .field__input[aria-invalid="true"] { border-color: #ffb4a8; }
.gt-field__error { display: none; font-size: 15px; font-weight: 600; color: #ffb4a8; margin: 8px 0 0 30px; }
.gt-field__error.is-shown { display: block; }
.gt-form__consent { font-size: 16px; line-height: 1.6; color: rgba(255, 255, 255, 0.8); margin: 4px 0 26px; max-width: 70ch; }
.gt-form__status { margin: 0 0 20px; padding: 15px 18px; border-radius: 12px; font-size: 16px; line-height: 1.5; }
.gt-form__status[hidden] { display: none; }
.gt-form__status--error { background: rgba(255, 180, 168, 0.12); border: 1px solid #ffb4a8; color: #ffd9d3; }
.gt-form__status--error a { color: #fff; font-weight: 700; }
.gt-form__submit { margin-top: 4px; }
.gt-submit { width: auto; min-width: 260px; display: inline-flex; align-items: center; justify-content: center; gap: 10px; }
.gt-btn__spinner {
  width: 18px; height: 18px; border: 2px solid currentColor; border-top-color: transparent;
  border-radius: 999px; animation: gt-spin 0.7s linear infinite;
}
@keyframes gt-spin { to { transform: rotate(360deg); } }
.gt-success { padding: 8px 0; }
.gt-success[hidden] { display: none; }
.gt-success__tick {
  width: 66px; height: 66px; border-radius: 999px; background: var(--gt-sky); color: var(--gt-navy);
  display: inline-flex; align-items: center; justify-content: center; margin-bottom: 20px;
}
.gt-success p { font-size: 16px; line-height: 1.65; margin: 12px 0 0; max-width: 56ch; }
.gt-success .gt-note a { color: #fff; font-weight: 700; }

/* ==========================================================================
   10. Mobile sticky CTA
   ========================================================================== */
.gt-sticky {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  /* Opaque, not 0.98. With no backdrop-filter behind it, that 2% bought no
     frosting - it only let whatever the bar was covering ghost through, and
     an FAQ question showing faintly across the price line reads as a
     rendering fault rather than as a translucent bar. */
  background: #fff;
  border-top: 1px solid #e0e0e0;
  padding: 8px 16px calc(10px + env(safe-area-inset-bottom));
  transform: translateY(115%); transition: transform 0.25s ease;
}
.gt-sticky.is-visible { transform: translateY(0); }
.gt-sticky__meta {
  display: flex; justify-content: center; gap: 6px; margin: 0 0 7px;
  font-size: 14px; line-height: 1.2; white-space: nowrap; overflow: hidden;
}
.gt-sticky__price { font-weight: 700; color: var(--gt-navy); }
.gt-sticky__time { font-weight: 600; color: #555; font-variant-numeric: tabular-nums; }
.gt-sticky .button { width: 100%; display: block; text-align: center; }
@media (min-width: 992px) { .gt-sticky { display: none !important; } }

/* Expired-offer state */
[data-gt-expired-hide][hidden] { display: none !important; }

/* ==========================================================================
   The base theme's own band backgrounds carry the look; they are recoloured to the
   GEOTECH ramp by geotech/recolor.py, so only the fallback colour is set here.
   ========================================================================== */
.text-width-icon, .banner-grid { background-color: var(--gt-ink); }
.gt-pain-close { color: #fff; }

/* the section eyebrow chips sit on dark bands too */
.banner-grid .sub-heading .subbg-text,
.text-width-icon .sub-heading .subbg-text { background: var(--gt-sky); color: var(--gt-navy); }


/* ==========================================================================
   The base theme layout details that its own copy never stressed
   ========================================================================== */

/* Proof cards: the screenshots read as the work, so they carry no scrims - the
   caption keeps its contrast from a text shadow instead, which costs nothing
   anywhere the shot is already dark and only shows where it is light (ARC's
   white header band under the eyebrow, its grey product band under the title).
   The theme's own flat card tint rides on ::before at 0.2; that is dropped to
   0.08 here so the shots stay bright against the dark band. */
.banner-grid .banner-image::before {
  background: rgba(2, 12, 31, 0.08) !important;
}
.banner-grid .banner-text .sub-heading,
.banner-grid .banner-text .heading-center {
  text-shadow: 0 1px 12px rgba(2, 12, 31, 0.75), 0 1px 3px rgba(2, 12, 31, 0.6);
}

/* Footer columns: The base theme splits the row 50 / 35.5 / 14.5, which suited a wide
   newsletter form beside a two-word label and a phone number. This footer
   carries a short blurb, a three-line address and a 28-character email, so the
   original split leaves a void under the blurb and starves the contact column
   - 14.5% is 186px at the 1280px container, and the email breaks mid-word
   ("getstarted@geotechen / gine.com"). 40 / 30 / 30 fits all three. The theme
   sets these widths through an id selector, so !important is the only way
   past it. Rows two and three are matched so the columns stay aligned. */
@media (min-width: 992px) {
  .footer #block-newsletter_cectcU,
  .footer #block-line_n3tVLP { width: 40% !important; }
  .footer #block-footer_text_Q9UjXL,
  .footer #block-footer_social_bhqwdE { width: 30% !important; }
  .footer #block-footer_text_BTnbxm,
  .footer #block-footer_text_EabYWG { width: 30% !important; }
}

/* The base theme reserves 250px of right padding inside the first footer block to
   keep its newsletter form clear of the next column. This block holds a short
   blurb and one button, so that padding only squeezes the text to 262px of a
   512px column and opens the gap in the middle of the footer. The theme's rule
   is `#block-newsletter_cectcU .footer__item`, so the extra `.footer` here is
   what carries this past it - no !important needed. */
@media (min-width: 1200px) {
  .footer #block-newsletter_cectcU .footer__item { padding-right: 48px; }
}

/* Tablet keeps the base theme's three-across split (42 / 33 / 25), which leaves the
   contact column ~180px - narrower than the 255px the email needs, so it
   breaks mid-word again. Give the blurb its own row and halve the other two. */
@media (min-width: 768px) and (max-width: 991px) {
  .footer #block-newsletter_cectcU,
  .footer #block-line_n3tVLP { width: 100% !important; }
  .footer #block-footer_text_Q9UjXL,
  .footer #block-footer_social_bhqwdE,
  .footer #block-footer_text_BTnbxm,
  .footer #block-footer_text_EabYWG { width: 50% !important; }
}

/* Checklist cards: same problem at the bottom, where the title sits. */
.team-wp .team-img::after {
  content: "";
  position: absolute;
  inset: 40% 0 0 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(2, 12, 31, 0), rgba(2, 12, 31, 0.86));
  pointer-events: none;
  border-radius: var(--block-border-radius-reduced);
}
/* The theme positions this absolutely over the bottom of the photo. Setting
   position here knocks it into normal flow, which drops white caption text
   onto the white page background — only the stacking order is needed. */
.team-wp .team-detail { z-index: 2; }

/* The base theme's team photos are portrait (710x900) so the image fills the card and
   the caption sits over it. These cards carry landscape renders instead, which
   collapse .team-img to 244px and leave the caption below the picture, so the
   card is held to the base theme's ratio and the image cropped to fill it. */
.team-wp .team-img { aspect-ratio: 710 / 900; }
.team-wp .team-img > img { width: 100%; height: 100%; object-fit: cover; }
.team-carousel .section__header, .team-carousel + * { position: relative; z-index: 2; }
.custom-template--27660350357826__team_carousel_EcUxi6 .section__header { position: relative; z-index: 2; }

/* footer sits on the brand's darkest surface, not pure black */
.footer, .copyright, .line-section > section { background-color: var(--gt-ink) !important; }


/* --- tap targets, prose size, and one flexbox width leak ----------------- */

/* The base theme's text-style link CTA is only ~14px tall; give it a real hit area. */
.btn-line, .style-btn-line {
  display: inline-flex !important;
  align-items: center;
  min-height: 48px;
}

/* The tab buttons collapse to 40px once their label wraps to one short line. */
.ap-navtabs__item {
  min-height: 48px;
}

/* checklist card subtitles are body copy, not a UI label */
.team-wp .team-job.text-small { font-size: 16px; line-height: 1.45; }

/* The carousel's fixed-width flex slides let the band grow past the viewport.
   It is clipped either way, but this keeps the band itself on the grid. */
.shopify-section--team-carousel .container { max-width: var(--container-max-width); }
.team-carousel, .team-carousel .ap-swiper, .team-carousel .swiper-wrapper { min-width: 0; max-width: 100%; }

/* --- hero: bring the promise and the CTA further up the fold ------------- */
.image-banner-2 { padding: 120px 0 60px !important; }
@media (max-width: 1199px) { .image-banner-2 { padding: 120px 0 60px !important; } }
@media (max-width: 767px)  { .image-banner-2 { padding: 120px 0 60px !important; } }
.image-banner-2 .banner__content-top.mb-40 { margin-bottom: 40px !important; }
.image-banner-2 .banner-content__heading.mb-xl-46 { margin-bottom: 20px !important; }
.gt-hero-actions { margin-top: 18px; }
.gt-hero-offer {
  display: inline-block;
  margin: 0 0 14px;
  padding: 8px 16px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(86, 199, 248, 0.45);
  font-size: 16px;
  font-weight: 700;
  color: #fff;
}
.gt-hero-offer b { color: var(--gt-sky-light); }
.gt-countdown { margin-bottom: 12px; }
.gt-hero-urgency { margin-bottom: 14px; }
.gt-hero-proof { margin-top: 12px; }
@media (min-width: 1200px) {
  .image-banner-2 .banner__content-bottom-last { width: 26% !important; }
}


/* ==========================================================================
   Mobile fold
   Measured at 360/390/430: the promise, the offer, the countdown and the one
   CTA all have to land above the fold, so everything that repeats elsewhere
   gets out of the way on small screens.
   ========================================================================== */
@media (max-width: 767px) {
  /* the urgency bar already carries the date in the hero's offer line */
  .gt-topbar__date { display: none; }
  .gt-topbar__inner { min-height: 40px; padding: 7px 0; gap: 2px 12px; }
  .gt-topbar__label, .gt-topbar__clock { font-size: 12px; letter-spacing: 0.06em; }

  .gt-header.header { padding: 8px 0; }
  .gt-header .header__logo-image { width: 124px; }

  /* the four hero meta labels repeat the urgency bar and the offer line */
  .image-banner-2 .banner__content-top { display: none !important; }

  /* the service list is context, not the action: it follows the CTA */
  .image-banner-2 .banner__content-bottom { display: flex; flex-direction: column; }
  .image-banner-2 .banner-content__description { order: 2; margin: 22px 0 0 !important; }
  .image-banner-2 .banner__content-bottom-last { order: 1; }

  /* the supporting line inherits .text-large (24px); 18px keeps it prominent
     without pushing the CTA off a 360x800 screen */
  .image-banner-2 .banner-content__description-2 .text-large { font-size: 18px; line-height: 1.4; }

  .gt-countdown { gap: 6px; }
  .gt-countdown__unit { min-width: 52px; padding: 6px 5px 7px; }
  .gt-countdown__unit b { font-size: 21px; }
  .gt-countdown__tz { flex: 1 0 100%; max-width: none; margin-top: 2px; }
}

/* the footer email is longer than the base theme's demo phone numbers */
.footer__item-description { overflow-wrap: anywhere; }


/* ==========================================================================
   Hero, at the base theme's proportions
   The base theme runs a transparent header over a full-bleed hero with a 160px
   headline and 198/343 padding. This headline is a whole sentence rather than
   two words, so it is scaled to the largest size that still sets each sentence
   on one line at 1440 — the airiness and the full-bleed header are restored
   as-is. Mobile keeps the compact fold from the block above.
   ========================================================================== */
@media (min-width: 1200px) {
  /* No divider under the header, and no fill that could make one. The base theme's
     header is transparent with a border-bottom of rgba(0,0,0,0) at every
     scroll position. Filling ours on scroll with rgba(2,12,31,.92) painted a
     flat #020c1f band over a hero that renders #010c1e, so the header's
     bottom edge showed as a full-width step of one unit per channel - tiny,
     but a dead-straight luminance edge is the one thing the eye always
     catches. With no fill the two are the same pixels and the edge is gone. */
  .gt-header.header,
  .gt-header.header.is-scrolled {
    background: transparent;
  }
  /* the hero runs full-bleed to the top and the header floats on it */
  .shopify-section--header { position: relative; z-index: 25; }
  #gt-hero { margin-top: -104px; }
  .image-banner-2 { padding: 198px 0 343px !important; }

  .image-banner-2 .banner-content__heading {
    font-size: 160px !important;
    line-height: 1.02 !important;
    letter-spacing: -0.04em !important;
  }
  .image-banner-2 .banner__content-top.mb-40 { margin-bottom: 40px !important; }
  .image-banner-2 .banner-content__heading.mb-xl-46 { margin-bottom: 26px !important; }
  .gt-hero-actions { margin-top: 14px; }
  .gt-hero-offer { margin-bottom: 12px; }

  /* The base theme runs the service list flush left, aligned with the headline */

  /* The base theme's action column is 367px of a 1410px container, i.e. 26%, which is
     what makes its supporting line wrap to four short lines above the button. */
  .image-banner-2 .banner__content-bottom-last { width: 26% !important; }

  /* The base theme's render is 701px at x=351 and starts partway down the headline,
     so it overlaps both the type and the bottom row. Matched here: 700px at
     right:27% puts it at the same x=351-1051, and the top is set to the same
     fraction of the hero's height. */
  .image-banner-2 .banner-content__image-child {
    top: 325px !important;
    right: 27% !important;
    max-width: 700px;
  }
}

@media (min-width: 1600px) {
  .image-banner-2 .banner-content__image-child { max-width: 820px; top: 400px !important; }
}

/* the render overlaps the action column from 992px up */
@media (min-width: 992px) {
  /* The base theme's render ends at x=1052 and its right column starts at x=1058, so
     they never touch. This column is 611px wide rather than 367px, because it
     carries the offer line, countdown, urgency line and proof line too, so the
     render does run under it. Unscrimmed, the white text falls to 1.65:1 over
     the bright part of the render. The scrim feathers out on its left so the
     render still reads as overlapping. */
  .image-banner-2 .banner__content-bottom-last { position: relative; }
  .image-banner-2 .banner__content-bottom-last::before {
    content: "";
    position: absolute;
    inset: -44px -48px -44px -64px;
    background: linear-gradient(to right,
        rgba(2, 12, 31, 0) 0,
        rgba(2, 12, 31, 0.90) 64px,
        rgba(2, 12, 31, 0.93) 100%);
    /* feather the top and bottom too, or the scrim reads as a hard-edged box
       wherever the render is bright behind it */
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 0, #000 44px, #000 calc(100% - 44px), rgba(0, 0, 0, 0) 100%);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 0, #000 44px, #000 calc(100% - 44px), rgba(0, 0, 0, 0) 100%);
    pointer-events: none;
    z-index: 0;
  }
  .image-banner-2 .banner__content-bottom-last > * { position: relative; z-index: 1; }
}

/* tablet keeps the base theme's step-down without the desktop overlay */
@media (min-width: 992px) and (max-width: 1199px) {
  .image-banner-2 .banner-content__heading { font-size: 72px !important; }
  .image-banner-2 { padding: 120px 0 60px !important; }
}


/* ==========================================================================
   Mobile pass
   Everything below was measured on the rendered page at 390x844, then
   re-checked at 360 and 430. Each rule answers a layout that only breaks
   once the desktop columns stack; none of it reaches a tablet or wider.
   ========================================================================== */
@media (max-width: 767px) {

  /* The 120px top pad belongs to the desktop hero, where the header is
     transparent and floats over a full-bleed band. On a phone the header is
     in normal flow and 106px tall, so the pad stacked on top of it and put
     226px of empty navy between the logo and the promise. */
  .image-banner-2 { padding: 32px 0 48px !important; }

  /* The service list is four <br>-separated spans. Left at body size under
     the CTA it reads as orphaned copy rather than a list; as a wrapped row
     of small caps with dot separators it reads as a capability strip. */
  .image-banner-2 .banner-content__description {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    row-gap: 4px;
  }
  .image-banner-2 .banner-content__description br { display: none; }
  .image-banner-2 .banner-content__description span {
    font-size: 12px;
    letter-spacing: 0.1em;
    color: rgba(255, 255, 255, 0.55);
  }
  .image-banner-2 .banner-content__description span + span::before {
    content: "\00b7";
    margin: 0 9px;
    color: rgba(255, 255, 255, 0.3);
  }

  /* The marquee is set at 140px for the desktop band. At 390 that puts two
     letters of "Shopify Store Rescue" across the whole screen, which reads
     as a cut-off heading rather than as moving type. */
  .text-scroll .textscroll-text { font-size: 32px !important; }

  /* The three process steps are desktop columns: the label sits right, the
     numeral left and the copy right, which scans as a rhythm side by side
     and as a zigzag once they stack full-width. Everything goes left, and
     the 30px label gap closes since there is no column to balance. */
  .gt-steps .counter-number {
    text-align: left !important;
    margin-bottom: 6px !important;
    font-size: 20px;
  }
  .gt-steps .counter-content-top { text-align: left !important; }
  /* the copy also carries the column's own offset - 220px wide pushed out by
     a 129px left margin - which is what held it in a narrow indented block
     a third of the way across the phone. */
  .gt-steps .description {
    text-align: left !important;
    width: auto !important;
    max-width: none;
    margin-left: 0 !important;
  }

  /* Proof cards: .banner-text is an absolute overlay 181px tall sitting on a
     211px card, so the captions cover the storefront art they exist to show
     - "Built for the drop" landed straight across ARC's own "IT'S OURS.".
     Below the shot the art is unobstructed and nothing needs a scrim. */
  .gt-proof-link .banner-text {
    position: static !important;
    padding: 14px 0 0 !important;
  }
  .gt-proof-link .sub-heading.mb-40 { margin-bottom: 10px !important; }
  .gt-proof-link .heading-center span { font-size: 22px; }
  .gt-proof-link .sub-heading,
  .gt-proof-link .heading-center { text-shadow: none; }

  /* arc-wordmark.webp is solid black - drawn for the light header it used to
     sit on. On the section's navy it needs inverting; the Lacomus mark is
     already cream and is left alone. */
  .gt-proof-link .project-logo[src*="arc-wordmark"] { filter: invert(1); }

  /* the two marks ship at different heights (ARC 27px, Lacomus 63px), which
     gave the two captions different rhythms once they stacked. */
  .gt-proof-link .project-logo { height: 26px; width: auto; }

  /* The "what changes" cards set their title beside their copy. At 360 the
     flex row squeezed the title to 62px, so "Built for the phone" broke to
     one word per line against a full-width paragraph. Stacked, both get the
     card's width. */
  .testimonial-scroll-content-bottom {
    flex-direction: column;
    align-items: flex-start !important;
    gap: 10px;
  }
  .testimonial-heading-bottom, .testimonial__content-bottom { width: 100% !important; }

  /* The theme's own mobile footer rule pulls every button in a footer column
     left by one button-height - .footer__item .btn-base gets
     margin-left: calc(-1 * var(--button-height)), which is -60px here. The
     column is centred, so that dragged the CTA 30px off centre under copy
     that stayed centred. Above 767 the column is left-aligned and the rule
     does not apply, so this is mobile-only too.
     body.gt-page carries the specificity: footer__q...css is injected by its
     section component at runtime and so lands after this file, which makes a
     matching !important on a matching selector lose on source order. */
  body.gt-page .footer__item .btn-base { margin-left: 0 !important; }
}

/* ==========================================================================
   Touch: no hover state
   A phone has no pointer, but a tap still applies :hover, and it stays applied
   until the next tap lands somewhere else. The theme's primary button empties
   its fill on hover - background-color goes to --cta-button-hover, which is
   rgba(0,0,0,0) - so the CTA turned into a hollow sky outline the moment it
   was touched and stayed that way. In the footer, over navy, that reads as a
   washed-out button. Every variant is held at its rest state wherever there
   is no real pointer, and :active carries the tap feedback instead.
   ========================================================================== */
@media (hover: none) {
  .btn-base:hover {
    background-color: var(--cta-button);
    color: var(--cta-text);
    border-color: var(--cta-button);
  }
  .btn-outline-red:hover {
    background-color: transparent;
    border-color: var(--gt-navy);
    color: var(--gt-navy);
  }
  .gt-on-dark .btn-outline-red:hover {
    background-color: transparent;
    border-color: rgba(255, 255, 255, 0.45);
    color: #fff;
  }
  .btn-outline-white:hover {
    background-color: transparent;
    border-color: #fff;
    color: #fff;
  }
  .button:active { transform: scale(0.98); }
}
