/* ==========================================================================
   COMPONENTS — shared across every page
   1. Buttons & links
   2. Eyebrow label
   3. Site header + navigation
   4. Site footer
   5. FAQ accordion
   6. Text links with arrow
   7. Photo hero (full-bleed image + dark overlay)
   8. Lightbox (full-screen image viewer)
   CTA stack and Trust badge (homepage hero, reusable) — before Headline caps
   Orbit carousel (Branding gallery, reusable) — before Headline caps
   Headline caps (uppercase headings with a colored second part) — at the end
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. BUTTONS — "arrow fill" (Mike, 7-oct-2026)
   Usage: <a class="btn btn--gold">…</a>   (optional: data-icon="i-calendar")
   Variants: --gold, --dark, --blue, --primary, --white
   A circle with an icon sits at the right end. On hover the circle grows
   until it fills the whole button, the label switches color as the fill
   passes over it, and the icon leaves to the right while a copy enters from
   the left. main.js › 22 adds the icon and the second label (.btn__mask).
   Model: hyperiux-vault.framer.website/arrow-fill-button
   Each variant only sets colors: --btn-bg / --btn-text (at rest) and
   --btn-fill / --btn-fill-text (circle, and the whole button on hover).
   -------------------------------------------------------------------------- */
.btn {
  --btn-circle: 36px;                 /* diameter of the icon circle */
  --btn-inset: 6px;                   /* gap between circle and button edge */
  --btn-pad: 26px;                    /* left padding */
  --btn-icon: 18px;
  --btn-dur: 0.45s;
  --btn-ease: cubic-bezier(0.785, 0.135, 0.15, 0.86);
  --btn-inset-y: calc((100% - var(--btn-circle)) / 2);
  --btn-inset-x: calc(100% - var(--btn-inset) - var(--btn-circle));
  --btn-bg: var(--gold-500);
  --btn-text: var(--black);
  --btn-fill: var(--white);
  --btn-fill-text: var(--black);

  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 10px calc(var(--btn-circle) + var(--btn-inset) + 14px) 10px var(--btn-pad);
  border-radius: var(--radius-pill);
  background: var(--btn-bg);
  color: var(--btn-text);
  font-family: var(--font-body);
  font-size: var(--text-16);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

.btn:hover {
  color: var(--btn-text);
  text-decoration: none;
}

/* The circle: grows into the full button on hover */
.btn::before {
  content: "";
  position: absolute;
  z-index: 1;
  inset: var(--btn-inset-y) var(--btn-inset) var(--btn-inset-y) var(--btn-inset-x);
  border-radius: var(--radius-pill);
  background: var(--btn-fill);
  pointer-events: none;
  transition: inset var(--btn-dur) var(--btn-ease);
}

/* Second copy of the label in the fill color, clipped to the circle */
.btn__mask {
  position: absolute;
  z-index: 2;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: inherit;
  padding: inherit;
  color: var(--btn-fill-text);
  clip-path: inset(var(--btn-inset-y) var(--btn-inset) var(--btn-inset-y) var(--btn-inset-x) round var(--radius-pill));
  pointer-events: none;
  transition: clip-path var(--btn-dur) var(--btn-ease);
}

.btn__icon {
  position: absolute;
  z-index: 3;
  top: 50%;
  right: var(--btn-inset);
  width: var(--btn-circle);
  height: var(--btn-circle);
  overflow: hidden;
  border-radius: 50%;
  color: var(--btn-fill-text);
  transform: translateY(-50%);
  pointer-events: none;
}

.btn__icon .icon {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--btn-icon);
  height: var(--btn-icon);
  transform: translate(-50%, -50%) scale(1);
  transition: transform var(--btn-dur) var(--btn-ease);
}

.btn__icon .icon--enter {
  transform: translate(-170%, -50%) scale(0);
}

@media (hover: hover) {
  .btn:hover::before { inset: 0; }
  .btn:hover .btn__mask { clip-path: inset(0 round var(--radius-pill)); }
  .btn:hover .icon--exit { transform: translate(70%, -50%) scale(0); }
  .btn:hover .icon--enter { transform: translate(-50%, -50%) scale(1); }
}

.btn:focus-visible::before { inset: 0; }
.btn:focus-visible .btn__mask { clip-path: inset(0 round var(--radius-pill)); }
.btn:focus-visible .icon--exit { transform: translate(70%, -50%) scale(0); }
.btn:focus-visible .icon--enter { transform: translate(-50%, -50%) scale(1); }

@media (prefers-reduced-motion: reduce) {
  .btn::before,
  .btn__mask,
  .btn__icon .icon {
    transition: none;
  }
}

/* Gold → fills white (default colors above). Always sits on dark sections. */
.btn--gold {
  --btn-bg: var(--gold-500);
  --btn-text: var(--black);
}

/* Navy → fills gold */
.btn--dark {
  --btn-bg: var(--blue-900);
  --btn-text: var(--white);
  --btn-fill: var(--gold-500);
  --btn-fill-text: var(--blue-900);
  min-width: 250px;
}

.btn--blue {
  --btn-bg: var(--blue-700);
  --btn-text: var(--white);
  --btn-fill: var(--gold-500);
  --btn-fill-text: var(--blue-900);
  font-weight: var(--weight-medium);
}

.btn--primary {
  --btn-bg: var(--blue-500);
  --btn-text: var(--white);
  --btn-fill: var(--gold-500);
  --btn-fill-text: var(--blue-900);
}

/* White button for blue backgrounds */
.btn--white {
  --btn-bg: var(--white);
  --btn-text: var(--blue-900);
  --btn-fill: var(--gold-500);
  --btn-fill-text: var(--blue-900);
  padding-block: 15px;
  font-size: var(--text-16);
  letter-spacing: var(--tracking-ui);
}

/* Sentence-case variant: "Let's talk about your brand" */
.btn--sentence {
  padding-block: 15px;
  font-size: var(--text-16);
  letter-spacing: var(--tracking-ui);
  text-transform: none;
}

/* Text link with icon (e.g. "Discuss your brand") */
.link-icon {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  color: var(--blue-900);
  font-size: var(--text-16);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  text-decoration: none;
}

.link-icon .icon {
  width: 19px;
  height: 19px;
}

.link-icon:hover {
  color: var(--blue-500);
}

/* Phones: a lighter button so it sits in proportion with the text around it
   (Mike, 8-oct-2026). Still 44px tall, the minimum comfortable tap size. */
@media (max-width: 478px) {
  .btn {
    --btn-circle: 32px;
    --btn-pad: 20px;
    --btn-icon: 16px;
    min-height: 44px;
    padding-block: 8px;
    font-size: var(--text-14);
  }

  .btn--dark {
    min-width: 190px;
  }

  .link-icon {
    font-size: var(--text-14);
  }
}

/* --------------------------------------------------------------------------
   2. EYEBROW (small label above a heading)
   -------------------------------------------------------------------------- */
.eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-16);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--blue-500);
}

/* Smaller label used on service pages: "SERVICE OVERVIEW / 01" */
.eyebrow--small {
  margin-bottom: 18px;
  font-size: var(--text-14);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-widest);
}

/* Gold label on dark backgrounds */
.eyebrow--on-dark {
  color: var(--gold-500);
}

/* --------------------------------------------------------------------------
   3. SITE HEADER
   Fixed bar: logo | nav pill | utility buttons.
   JS sets data-tone="light" when the header sits over a light section,
   which switches the logo and nav to their dark-on-light version.
   Motion (approved 1-oct-2026): rolling letters on the links, dropdown
   fade + dash, header slides away on scroll down and back on scroll up.
   All of it stops with "reduce motion".
   -------------------------------------------------------------------------- */
.site-header {
  position: fixed;
  top: 16px;
  /* Lines up with the edges of the layout grid */
  left: max(var(--grid-margin), (100% - var(--container-max)) / 2);
  right: max(var(--grid-margin), (100% - var(--container-max)) / 2);
  z-index: var(--z-header);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  font-family: var(--font-body);
  transition: transform var(--dur-roll) var(--ease-roll);
}

/* Set by JS while scrolling down. Only applied when hidden: a transform on
   the header would otherwise become the anchor of the fixed mobile panel. */
.site-header.is-hidden {
  transform: translateY(calc(-100% - 32px));
}

/* Progressive blur (Mike, 7-oct-2026; model: arpeggio.framer.website).
   A glass edge across the top of the screen: 8 stacked layers, each with
   twice the blur of the one before and a mask that only shows it in its own
   band. Blur is strongest at the very top and fades to nothing at the bottom
   of the strip, so content looks like it dissolves as it scrolls under the
   header. It sits behind the header and stays when the header slides away.
   Static: nothing moves, so there is nothing to switch off for "reduce motion". */
.header-blur {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--header-blur-height);
  z-index: var(--z-header-blur);
  pointer-events: none;
}

.header-blur__layer {
  position: absolute;
  inset: 0;
  -webkit-backdrop-filter: blur(var(--blur));
  backdrop-filter: blur(var(--blur));
  -webkit-mask-image: var(--mask);
  mask-image: var(--mask);
}

/* Masks read from the bottom of the strip (0%) up to the top (100%) */
.header-blur__layer:nth-child(1) { --blur: 0.4px;  --mask: linear-gradient(to top, transparent 0%,    #000 12.5%, #000 25%,   transparent 37.5%); }
.header-blur__layer:nth-child(2) { --blur: 0.8px;  --mask: linear-gradient(to top, transparent 12.5%, #000 25%,   #000 37.5%, transparent 50%); }
.header-blur__layer:nth-child(3) { --blur: 1.6px;  --mask: linear-gradient(to top, transparent 25%,   #000 37.5%, #000 50%,   transparent 62.5%); }
.header-blur__layer:nth-child(4) { --blur: 3.2px;  --mask: linear-gradient(to top, transparent 37.5%, #000 50%,   #000 62.5%, transparent 75%); }
.header-blur__layer:nth-child(5) { --blur: 6.4px;  --mask: linear-gradient(to top, transparent 50%,   #000 62.5%, #000 75%,   transparent 87.5%); }
.header-blur__layer:nth-child(6) { --blur: 12.8px; --mask: linear-gradient(to top, transparent 62.5%, #000 75%,   #000 87.5%, transparent 100%); }
.header-blur__layer:nth-child(7) { --blur: 25.6px; --mask: linear-gradient(to top, transparent 75%,   #000 87.5%, #000 100%); }
.header-blur__layer:nth-child(8) { --blur: 51.2px; --mask: linear-gradient(to top, transparent 87.5%, #000 100%); }

.site-header__logo {
  justify-self: start;
  width: 150px;
}

.site-header__logo img {
  width: 100%;
  max-height: 48px;
  object-fit: contain;
  object-position: left center;
}

/* Two files, one visible at a time: the full-color logo over light sections,
   the all-white one over dark sections (default until JS sets the tone). */
.site-header__logo-img--color {
  display: none;
}

.site-header[data-tone="light"] .site-header__logo-img--color {
  display: block;
}

.site-header[data-tone="light"] .site-header__logo-img--white {
  display: none;
}

/* ---------- Nav pill (frosted glass) ---------- */
.site-nav {
  --nav-fg: rgb(255 255 255 / 0.92);
  --nav-current: var(--gold-500);        /* page you are on */
  --nav-tint: rgb(255 255 255 / 0.14);   /* static hover (reduce motion only) */
  justify-self: center;
  padding: 0 10px;
  border: 1px solid var(--glass-dark-border);
  border-radius: var(--radius-m);
  background: var(--glass-dark-bg);
  box-shadow: var(--shadow-s);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
}

.site-header[data-tone="light"] .site-nav {
  --nav-fg: rgb(27 27 30 / 0.82);
  --nav-current: var(--gold-700);        /* darker gold: readable on light glass */
  --nav-tint: rgb(27 27 30 / 0.08);
  background: var(--glass-light-bg);
  border-color: var(--glass-light-border);
  box-shadow: var(--shadow-s);
}

.site-nav__list {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav__item {
  position: relative;
}

.site-nav__link {
  display: flex;
  align-items: center;
  gap: 5px;
  min-height: 50px;
  padding: 0 11px;
  border-radius: var(--radius-s);
  color: var(--nav-fg);
  font-size: var(--text-14);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-none);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

/* Current page: gold text, same as the current item inside the dropdown.
   Hover feedback is the rolling text below. */
.site-nav__link[aria-current="page"],
.site-nav__link.is-current {
  color: var(--nav-current);
}

.site-nav__link .icon {
  width: 14px;
  height: 14px;
}

.site-nav__toggle[aria-expanded="true"] .icon {
  transform: rotate(180deg);
}

/* Items that only show inside the mobile menu */
.site-nav__item--mobile {
  display: none;
}

/* ---------- Rolling text ----------
   main.js splits each label into letters, twice, inside .roll. The box is one
   line tall and clips, so only one copy shows. On hover every letter slides up
   by one line (15ms after the previous one) and the second copy takes its place. */
.roll {
  --roll-h: 1.5em;
  display: inline-block;
  height: var(--roll-h);
  overflow: hidden;
  line-height: var(--roll-h);
  white-space: nowrap;
}

.roll__row {
  display: block;
}

.roll__ch {
  display: inline-block;
  transition: transform var(--dur-roll) var(--ease-roll);
  transition-delay: calc(var(--i) * var(--stagger-roll));
}

@media (hover: hover) and (min-width: 992px) {
  .site-nav__link:hover .roll__ch,
  .site-nav__link:focus-visible .roll__ch,
  .site-nav__item:hover > .site-nav__link .roll__ch,
  .site-nav__link[aria-expanded="true"] .roll__ch {
    transform: translateY(-100%);
  }
}

/* Phones & tablets: plain text, no second copy */
@media (max-width: 991px) {
  .roll {
    display: inline;
    height: auto;
    overflow: visible;
    line-height: inherit;
  }

  .roll__row + .roll__row {
    display: none;
  }

  .roll__ch {
    display: inline;
    transition: none;
  }
}

/* ---------- Dropdown ---------- */
.site-nav__dropdown {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  display: grid;
  gap: 2px;
  min-width: 270px;
  margin: 0;
  padding: 12px;
  list-style: none;
  border: 1px solid var(--on-dark-line-soft);
  border-radius: var(--radius-m);
  background: var(--ink);
  box-shadow: var(--shadow-m);
  /* Closed: rises into place while it fades in. visibility waits for the fade-out. */
  visibility: hidden;
  opacity: 0;
  transform: translateY(14px);
  pointer-events: none;
  transition:
    opacity var(--dur-menu) ease,
    transform var(--dur-menu) var(--ease-roll),
    visibility 0s linear var(--dur-menu);
}

/* Invisible bridge so the menu doesn't close while the pointer crosses the gap */
.site-nav__dropdown::before {
  content: "";
  position: absolute;
  inset: -10px 0 auto;
  height: 10px;
}

.site-nav__item.is-open > .site-nav__dropdown {
  visibility: visible;
  opacity: 1;
  transform: none;
  pointer-events: auto;
  transition-delay: 0s;
}

@media (hover: hover) and (min-width: 992px) {
  .site-nav__item--has-dropdown:hover > .site-nav__dropdown {
    visibility: visible;
    opacity: 1;
    transform: none;
    pointer-events: auto;
    transition-delay: 0s;
  }
}

/* Dropdown links: a short dash grows in on the left and the text steps right */
.site-nav__dropdown a {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 40px;
  padding: 9px 11px 9px 24px;
  border-radius: var(--radius-s);
  color: var(--white);
  font-size: var(--text-14);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;   /* the menu grows to fit its longest label */
  transition: padding-left var(--dur-menu) ease;
}

.site-nav__dropdown a::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 10px;
  width: 0;
  height: 1px;
  background: currentColor;
  transition: width var(--dur-menu) ease;
}

.site-nav__dropdown a:hover,
.site-nav__dropdown a:focus-visible,
.site-nav__dropdown a[aria-current="page"] {
  padding-left: 29px;
}

.site-nav__dropdown a:hover::before,
.site-nav__dropdown a:focus-visible::before,
.site-nav__dropdown a[aria-current="page"]::before {
  width: 10px;
}

/* Current page inside a dropdown: gold, and the dash stays on */
.site-nav__dropdown a[aria-current="page"] {
  color: var(--gold-500);
  font-weight: var(--weight-semibold);
}

/* ---------- Reduce motion: no sliding, no rolling ----------
   Hover keeps a plain tint so links still react. */
@media (prefers-reduced-motion: reduce) {
  .site-header,
  .site-nav__dropdown,
  .site-nav__dropdown a,
  .site-nav__dropdown a::before,
  .roll__ch {
    transition: none;
  }

  .roll__ch {
    transform: none !important;
  }
}

@media (prefers-reduced-motion: reduce) and (hover: hover) {
  .site-nav__link:hover,
  .site-nav__item:hover > .site-nav__link {
    background: var(--nav-tint);
  }
}

/* ---------- Utility button (Contact) ---------- */
.site-header__utility {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 8px;
}

/* An "arrow fill" button (› 1. BUTTONS), sized for the header.
   Markup: <a class="btn header-btn header-btn--contact"> */
.header-btn {
  --btn-circle: 32px;
  --btn-inset: 6px;
  --btn-pad: 18px;
  --btn-icon: 16px;
  min-height: 44px;
  padding-block: 0;
  font-size: var(--text-14);
  line-height: var(--leading-none);
  letter-spacing: var(--tracking-ui);
}

/* White on dark sections, ink on light ones; fills gold either way */
.header-btn--contact {
  --btn-bg: var(--white);
  --btn-text: var(--ink);
  --btn-fill: var(--gold-500);
  --btn-fill-text: var(--ink);
}

.site-header[data-tone="light"] .header-btn--contact {
  --btn-bg: var(--ink);
  --btn-text: var(--white);
}

/* ---------- Mobile menu button ---------- */
.menu-button {
  display: none;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-pill);
  background: var(--ink);
  color: var(--white);
}

.menu-button .icon {
  width: 22px;
  height: 22px;
}

.menu-button .icon--close,
.menu-button[aria-expanded="true"] .icon--menu {
  display: none;
}

.menu-button[aria-expanded="true"] .icon--close {
  display: block;
}

/* ---------- Header: medium screens ---------- */
@media (max-width: 1150px) and (min-width: 992px) {
  .site-header__logo {
    width: 128px;
  }

  .site-nav__link {
    padding: 0 8px;
    font-size: 0.8125rem;
  }
}

/* ---------- Header: tablet & mobile ---------- */
@media (max-width: 991px) {
  :root {
    --header-offset: 112px;
    --header-blur-height: 80px;
  }

  .site-header {
    top: 8px;
    grid-template-columns: auto 1fr auto;
    gap: 10px;
  }

  .site-header__logo {
    width: 118px;
  }

  .site-header__utility {
    grid-column: 2;
  }

  .header-btn--contact {
    --btn-circle: 30px;
    --btn-pad: 14px;
    min-height: 42px;
    font-size: var(--text-12);
  }

  .menu-button {
    display: grid;
    grid-column: 3;
  }

  /* The nav pill becomes a full-width panel under the header */
  .site-nav {
    position: fixed;
    top: 64px;
    left: 0;
    right: 0;
    z-index: var(--z-menu);
    justify-self: stretch;
    display: none;
    max-height: calc(100dvh - 64px);
    padding: 12px 20px 20px;
    overflow-y: auto;
    border: 0;
    border-radius: 0 0 var(--radius-m) var(--radius-m);
    background: var(--ink);
    box-shadow: var(--shadow-m);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    --nav-fg: var(--white);
  }

  /* The mobile panel is solid in both tones: no glass, so it stays readable */
  .site-header[data-tone="light"] .site-nav {
    --nav-fg: var(--white);
    --nav-current: var(--gold-500);
    --nav-tint: rgb(255 255 255 / 0.14);
    background: var(--ink);
    border-color: transparent;
    box-shadow: var(--shadow-m);
  }

  .site-nav.is-open {
    display: block;
  }

  .site-nav__list {
    flex-direction: column;
    align-items: stretch;
  }

  .site-nav__item {
    border-bottom: 1px solid var(--on-dark-line-soft);
  }

  .site-nav__item--mobile {
    display: block;
  }

  .site-nav__link {
    justify-content: space-between;
    width: 100%;
    min-height: 49px;
    padding: 8px 4px;
    border-radius: 0;
    font-size: var(--text-16);
  }

  /* Dropdown becomes an accordion: no fade, just open/closed */
  .site-nav__dropdown {
    position: static;
    display: none;
    min-width: 0;
    margin-bottom: 10px;
    box-shadow: none;
    visibility: visible;
    opacity: 1;
    transform: none;
    pointer-events: auto;
    transition: none;
  }

  .site-nav__item.is-open > .site-nav__dropdown {
    display: grid;
  }
}

@media (max-width: 478px) {
  .site-header__logo {
    width: 108px;
  }

  .header-btn--contact {
    --btn-pad: 11px;
  }
}

/* --------------------------------------------------------------------------
   4. SITE FOOTER (redesigned 4-oct-2026, Mike)
   One dark "office" scene: contact button on top, Lobo pointing in the middle,
   Services and Company menus at his sides and a looping band of client logos
   behind him. Legal bar underneath. The top fades from --scene-dark, the
   same color as the closing CTA (.closing-cta) that sits right above it on
   some pages, so both read as one section.
   The logo band is an approved exception to the "no animations" rule
   (Mike, 4-oct-2026). Speed: --footer-ticker-duration (longer = slower).
   Lobo's size: --lobo-w on phones/tablets, --lobo-h on desktop.
   -------------------------------------------------------------------------- */
.site-footer {
  position: relative;
  overflow: hidden;
  background: var(--black);
  color: var(--on-dark-text);
  font-size: var(--text-16);
}

.site-footer a {
  color: inherit;
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--white);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The scene. Phones and tablets: everything stacks, Lobo stands on the legal bar. */
.footer-stage {
  --lobo-w: min(78vw, 360px);
  --lobo-h: calc(var(--lobo-w) * 1.447); /* picture ratio 470 x 680 */
  --footer-ticker-duration: 80s;
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: var(--space-l);
  background:
    linear-gradient(to bottom, var(--scene-dark) 0%, rgb(0 0 0 / 0.2) 35%, rgb(0 0 0 / 0.4) 65%, rgb(0 0 0 / 0.92) 90%, var(--black) 100%),
    var(--black) url("../images/footer/footer-office.webp") center top / cover no-repeat;
}

/* Menus: two columns under the headline */
.footer-menus {
  position: relative;
  z-index: 4;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  width: min(100% - 24px, 520px);
  margin-top: var(--space-l);
  text-align: center;
  white-space: nowrap;
}

.footer-menu h2 {
  margin-bottom: var(--space-2xs);
  color: var(--on-dark-text);
  font-family: var(--font-body);
  font-size: var(--text-12);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}

.footer-menu ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer .footer-menu a {
  display: block;
  padding-block: 5px;
  color: var(--white);
  font-family: var(--font-display);
  font-size: var(--text-m);
  font-weight: var(--weight-bold);
  line-height: var(--leading-compact);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}

.site-footer .footer-menu a:hover {
  color: var(--gold-500);
  text-decoration: none;
}

/* Lobo */
.footer-stage__lobo {
  position: relative;
  z-index: 3;
  width: var(--lobo-w);
  height: auto;
  margin-top: var(--space-l);
  pointer-events: none;
}

/* Band of client logos, behind Lobo */
.footer-ticker {
  position: absolute;
  z-index: 2;
  right: 0;
  bottom: calc(var(--lobo-h) * 0.66);
  left: 0;
  overflow: hidden;
  pointer-events: none;
}

.footer-ticker__track {
  display: flex;
  width: max-content;
  animation: footer-ticker-scroll var(--footer-ticker-duration) linear infinite;
}

.site-footer .footer-ticker__group {   /* prefix beats base.css ul[role="list"] { padding: 0 } */
  display: flex;
  align-items: center;
  gap: var(--space-l);
  margin: 0;
  padding: 0 var(--space-l) 0 0; /* same as the gap, so the loop has no seam */
  list-style: none;
}

.footer-ticker__group li {
  flex: none;
}

.footer-ticker__group img {
  width: auto;
  max-width: 110px;
  height: auto;
  max-height: 38px;
}

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

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

/* Contact button, at the top of the scene */
.site-footer .footer-stage__cta {
  position: relative;
  z-index: 5;
  color: var(--black);
}

.site-footer .footer-stage__cta:hover {
  color: var(--black);
  text-decoration: none;
}

/* Legal bar */
.footer-bottom {
  position: relative;
  background: var(--blue-900);
  font-size: var(--text-14);
  text-align: center;
}

.footer-bottom p {
  padding-block: var(--space-s);
  border-bottom: 1px solid var(--on-dark-line);
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 24px;
  padding-block: var(--space-s);
}

/* Social profiles: two icon links. They sit inside the Company menu in the
   page; on phones and tablets they are centered under both menus (the menus
   block keeps 52px free for them), on desktop under the Company list. */
.footer-menus {
  padding-bottom: 52px;
}

.footer-social {
  position: absolute;
  bottom: 0;
  left: 50%;
  display: flex;
  gap: 4px;
  transform: translateX(-50%);
}

.site-footer .footer-social a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
}

.footer-social .icon {
  width: 22px;
  height: 22px;
}

@media (max-width: 374px) {
  .site-footer .footer-menu a {
    font-size: var(--text-14);
  }
}

/* Desktop: menus move to Lobo's sides and he grows. */
@media (min-width: 992px) {
  .footer-stage {
    --lobo-h: clamp(480px, 50vw, 720px);
    --lobo-top: 130px; /* distance from the top of the footer to Lobo's ears */
    height: calc(var(--lobo-top) + var(--lobo-h));
  }

  .footer-menus {
    position: static;
    display: block;
    width: auto;
    margin: 0;
    padding-bottom: 0;
  }

  .footer-social {
    top: 100%;
    bottom: auto;
    margin-top: 6px;
  }

  .footer-social .icon {
    width: 26px;
    height: 26px;
  }

  .footer-menu {
    position: absolute;
    z-index: 4;
    top: 52%;
    transform: translate(-50%, -50%);
    white-space: nowrap;
  }

  .footer-menu--services { left: 18%; }
  .footer-menu--company { left: 84%; }

  .footer-menu h2 {
    margin-bottom: var(--space-xs);
  }

  .site-footer .footer-menu a {
    padding-block: 3px;
    font-size: var(--text-l);
  }

  .footer-stage__lobo {
    position: absolute;
    bottom: 0;
    left: 50%;
    width: auto;
    height: var(--lobo-h);
    margin: 0;
    transform: translateX(-50%);
  }

  .footer-ticker {
    bottom: 11%;
  }

  .site-footer .footer-ticker__group {
    gap: var(--space-xl);
    padding-right: var(--space-xl);
  }

  .footer-ticker__group img {
    max-width: 150px;
    max-height: 52px;
  }

  .footer-bottom .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s);
    min-height: 64px;
  }

  .footer-bottom p,
  .footer-legal {
    padding-block: 0;
    border: 0;
  }
}

/* Wide screens: Lobo continues over the legal bar, down to the end of the page */
@media (min-width: 1200px) {
  .footer-stage {
    height: calc(var(--lobo-top) + var(--lobo-h) - 64px);
  }

  .site-footer .footer-menu a {
    font-size: var(--text-xl);
  }

  .footer-stage__lobo {
    bottom: -64px;
  }

  .footer-bottom .container {
    height: 64px;
  }
}

/* Closing CTA: eyebrow + big headline right above the footer (services,
   About, Who We Help). Same dark color as the top of the footer; the
   footer's button acts as its button. */
.closing-cta {
  margin-bottom: -1px; /* overlaps the footer by 1px so no hairline shows between them */
  padding-top: var(--space-section);
  padding-bottom: 1px;
  background: var(--scene-dark);
  color: var(--white);
  text-align: center;
}

:is(h1, h2, h3).closing-cta__title {
  font-size: var(--text-4xl);
  text-wrap: balance;
}

@media (min-width: 992px) {
  :is(h1, h2, h3).closing-cta__title {
    font-size: var(--text-6xl);
  }
}

/* --------------------------------------------------------------------------
   5. FAQ ACCORDION (Mike, 7-oct-2026)
   Model: "Interactive Accordion" by Jatin Yadav (21st.dev): numbered rows, a
   circle that fills behind the number, a line that grows under the row and a
   plus that turns into an x. Native <details>/<summary>, so it opens and
   closes without JavaScript; main.js › 17 only adds the spring height
   animation and keeps one row open at a time.
   Markup (the page generators write it; the first row starts open):
     <details class="faq__item" open>
       <summary class="faq__question">
         <span class="faq__number" aria-hidden="true">01</span>
         <h3>Question</h3>
         <span class="faq__icon" aria-hidden="true"><svg …></svg></span>
       </summary>
       <div class="faq__panel"><p class="faq__answer">Answer</p></div>
     </details>
   Add .faq--strong for semibold questions.
   Motion is an approved exception to "no animations" and stops with "reduce
   motion". The springs below are the original stiffness/damping values
   turned into CSS linear() curves; main.js reads --faq-spring-line and
   --faq-time-line for the height of the answer panel.
   -------------------------------------------------------------------------- */
.faq {
  --faq-ink: var(--ink);
  --faq-muted: var(--gray-700);
  --faq-line: var(--gray-300);
  --faq-circle: 40px;
  --faq-gap: 24px;
  /* pop: stiffness 400, damping 25 (zeta 0.62), settles in 0.50s */
  --faq-time-pop: 495ms;
  --faq-spring-pop: linear(0, 0.035, 0.125, 0.246, 0.382, 0.519, 0.647, 0.761, 0.856, 0.933, 0.992, 1.033, 1.06, 1.075, 1.081, 1.079, 1.073, 1.063, 1.052, 1.041, 1.031, 1.021, 1.013, 1.007, 1.002, 0.998, 0.996, 0.994, 0.994, 0.994, 0.994, 0.995, 0.996, 0.996, 0.997, 1);
  /* title: stiffness 400, damping 30 (zeta 0.75), settles in 0.39s */
  --faq-time-title: 390ms;
  --faq-spring-title: linear(0, 0.022, 0.079, 0.159, 0.251, 0.349, 0.446, 0.539, 0.625, 0.702, 0.77, 0.828, 0.877, 0.917, 0.949, 0.975, 0.994, 1.008, 1.017, 1.024, 1.027, 1.028, 1.028, 1.027, 1.025, 1.022, 1.019, 1.017, 1.014, 1.011, 1.009, 1.007, 1.005, 1.004, 1.003, 1);
  /* icon: stiffness 300, damping 20 (zeta 0.58), settles in 0.57s */
  --faq-time-icon: 565ms;
  --faq-spring-icon: linear(0, 0.035, 0.124, 0.247, 0.386, 0.527, 0.661, 0.78, 0.881, 0.962, 1.024, 1.066, 1.093, 1.106, 1.108, 1.103, 1.092, 1.078, 1.063, 1.048, 1.033, 1.021, 1.011, 1.002, 0.996, 0.992, 0.989, 0.988, 0.988, 0.989, 0.99, 0.992, 0.994, 0.995, 0.997, 1);
  /* line: stiffness 300, damping 30 (zeta 0.87), settles in 0.46s */
  --faq-time-line: 460ms;
  --faq-spring-line: linear(0, 0.023, 0.08, 0.157, 0.246, 0.337, 0.427, 0.513, 0.591, 0.661, 0.723, 0.776, 0.822, 0.86, 0.892, 0.918, 0.939, 0.956, 0.969, 0.979, 0.987, 0.993, 0.997, 1, 1.002, 1.003, 1.004, 1.004, 1.004, 1.004, 1.004, 1.004, 1.003, 1.003, 1.002, 1);
  /* answer: stiffness 300, damping 25 (zeta 0.72), settles in 0.44s */
  --faq-time-answer: 435ms;
  --faq-spring-answer: linear(0, 0.021, 0.075, 0.151, 0.241, 0.337, 0.433, 0.527, 0.614, 0.693, 0.763, 0.824, 0.876, 0.918, 0.953, 0.98, 1.001, 1.016, 1.026, 1.033, 1.037, 1.038, 1.037, 1.035, 1.032, 1.029, 1.025, 1.022, 1.018, 1.015, 1.012, 1.009, 1.007, 1.005, 1.003, 1);
}

.faq__question {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--faq-gap);
  padding: 20px 4px;
  border-bottom: 1px solid var(--faq-line);
  cursor: pointer;
  list-style: none;
  -webkit-tap-highlight-color: transparent;
}

.faq__question::-webkit-details-marker {
  display: none;
}

.faq__question:focus-visible {
  outline: 2px solid var(--blue-500);
  outline-offset: 2px;
}

/* Line that grows from the left over the grey one: a third on hover, full width when open */
.faq__question::after {
  content: "";
  position: absolute;
  bottom: -1px;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--faq-ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--faq-time-line) var(--faq-spring-line);
}

/* Number: the circle fills behind it */
.faq__number {
  position: relative;
  isolation: isolate;
  display: grid;
  flex: none;
  place-items: center;
  width: var(--faq-circle);
  height: var(--faq-circle);
  color: var(--faq-muted);
  font-size: var(--text-14);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-ui);
  transition: color 0.2s ease;
}

.faq__number::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 50%;
  background: var(--faq-ink);
  opacity: 0;
  transform: scale(0);
  transition: transform var(--faq-time-pop) var(--faq-spring-pop),
              opacity var(--faq-time-pop) var(--faq-spring-pop);
}

.faq__question h3 {
  color: var(--faq-muted);
  font-size: var(--text-l);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-snug);
  transition: transform var(--faq-time-title) var(--faq-spring-title),
              color 0.25s ease;
}

.faq--strong .faq__question h3 {
  font-weight: var(--weight-semibold);
}

/* Plus that turns into an x when the row opens */
.faq__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 32px;
  height: 32px;
  margin-left: auto;
  color: var(--faq-ink);
  opacity: 0.4;
  transition: transform var(--faq-time-icon) var(--faq-spring-icon),
              opacity 0.2s ease;
}

.faq__icon svg {
  width: 16px;
  height: 16px;
}

/* Hover (mouse only): hint of the open state */
@media (hover: hover) {
  .faq__question:hover::after {
    transform: scaleX(0.3);
  }

  .faq__question:hover .faq__number::before {
    opacity: 0.1;
    transform: scale(0.85);
  }

  .faq__question:hover h3 {
    color: var(--faq-ink);
    transform: translateX(4px);
  }

  .faq__question:hover .faq__icon {
    opacity: 1;
  }
}

/* Open row (not while it is closing) */
.faq__item[open]:not(.is-closing) .faq__question::after {
  transform: scaleX(1);
}

.faq__item[open]:not(.is-closing) .faq__number {
  color: var(--white);
}

.faq__item[open]:not(.is-closing) .faq__number::before {
  opacity: 1;
  transform: scale(1);
}

.faq__item[open]:not(.is-closing) .faq__question h3 {
  color: var(--faq-ink);
  transform: translateX(4px);
}

.faq__item[open]:not(.is-closing) .faq__icon {
  opacity: 1;
  transform: rotate(45deg);
}

/* Answer: lines up under the question text */
.faq__answer {
  padding: 24px 48px 24px calc(var(--faq-circle) + var(--faq-gap));
  color: var(--color-text-strong);
  font-size: var(--text-16);
  line-height: var(--leading-relaxed);
}

@media (max-width: 767px) {
  .faq {
    --faq-circle: 36px;
    --faq-gap: 14px;
  }

  .faq__question {
    padding-block: 16px;
  }

  .faq__answer {
    padding: 14px 8px 22px calc(var(--faq-circle) + var(--faq-gap));
  }
}

@media (prefers-reduced-motion: reduce) {
  .faq__question::after,
  .faq__number,
  .faq__number::before,
  .faq__question h3,
  .faq__icon {
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   6. TEXT LINK WITH ARROW ("View work →", "Learn more →")
   Takes the color of its parent; add --gold for the accent version.
   -------------------------------------------------------------------------- */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 4px;
  color: inherit;
  font-size: var(--text-14);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-ui);
  line-height: var(--leading-snug);
  text-transform: uppercase;
  text-decoration: none;
}

.link-arrow .icon {
  width: 16px;
  height: 16px;
}

.link-arrow:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

.link-arrow--gold {
  color: var(--gold-500);
}

/* --------------------------------------------------------------------------
   7. PHOTO HERO
   Full-bleed photo with a navy overlay and text anchored at the bottom.
   Used by: Who We Help (index), the 7 industry pages, About.
   Modifier: .photo-hero--low pushes the text further down (About).
   Entrance (Mike, 7-oct-2026; model: hero of luzen-temlis.webflow.io, its
   "Hero One BG" interaction): when the page loads the photo starts zoomed in
   (1.5×) and blurred (100 px), sharpens in 0.7 s and zooms out to 1× in
   1.5 s, both easing out (easeOutQuad). Only the photo moves; the veil and
   the text stay put. Plain CSS; no entrance with "reduce motion".
   -------------------------------------------------------------------------- */
.photo-hero {
  position: relative;
  display: flex;
  min-height: max(774px, 86svh);
  padding-bottom: 48px;
  overflow: hidden;
  background: var(--blue-900);
  color: var(--white);
  isolation: isolate;
}

.photo-hero__image,
.photo-hero__overlay {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
}

.photo-hero__image {
  object-fit: cover;
}

@media (prefers-reduced-motion: no-preference) {
  .photo-hero__image {
    animation:
      photo-hero-zoom 1500ms cubic-bezier(0.5, 1, 0.89, 1),
      photo-hero-focus 700ms cubic-bezier(0.5, 1, 0.89, 1);
  }
}

@keyframes photo-hero-zoom {
  from { transform: scale(1.5); }
  to   { transform: scale(1); }
}

@keyframes photo-hero-focus {
  from { filter: blur(100px); }
  to   { filter: blur(0); }
}

.photo-hero__overlay {
  background: rgb(17 22 39 / 0.52);
}

.photo-hero__inner {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  gap: 21px;
  padding-top: calc(var(--header-offset) + 60px);
}

.photo-hero__title {
  max-width: 850px;
  font-size: var(--text-7xl);
  font-weight: var(--weight-regular);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

.photo-hero__text {
  width: 100%;
  margin-top: 30px;
  padding-top: 22px;
  border-top: 1px solid var(--on-dark-line-strong);
  font-size: var(--text-20);
  line-height: var(--leading-normal);
}

.photo-hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 21px;
  margin-top: 9px;
}

.photo-hero--low .photo-hero__inner {
  padding-top: calc(var(--header-offset) + 260px);
}

/* Darker at the bottom so the text stays readable over busy images */
.photo-hero--low .photo-hero__overlay {
  background: linear-gradient(to top, rgb(17 22 39 / 0.88) 0%, rgb(17 22 39 / 0.52) 50%);
}

.photo-hero__text--narrow {
  /* keeps the divider line full width while the text wraps at ~560px */
  padding-right: max(0px, calc(100% - 560px));
}

@media (max-width: 767px) {
  .photo-hero {
    min-height: 680px;
  }

  .photo-hero--low .photo-hero__inner {
    padding-top: calc(var(--header-offset) + 200px);
  }
}

/* --------------------------------------------------------------------------
   8. LIGHTBOX
   Native <dialog> opened by main.js from any list marked [data-lb-gallery].
   Layout: top bar (counter + tools), image in the middle, side arrows,
   caption band at the bottom. No animations.
   -------------------------------------------------------------------------- */
.lightbox {
  width: 100vw;
  max-width: none;
  height: 100dvh;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: rgb(0 0 0 / 0.94);
  color: var(--white);
  overflow: hidden;
}

.lightbox[open] {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
}

.lightbox::backdrop {
  background: rgb(0 0 0 / 0.94);
}

.lightbox__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 12px 8px 20px;
  background: rgb(0 0 0 / 0.35);
}

.lightbox__counter {
  font-size: var(--text-14);
  font-variant-numeric: tabular-nums;
  opacity: 0.8;
}

.lightbox__tools {
  display: flex;
  gap: 4px;
}

.lightbox__tool,
.lightbox__nav {
  display: grid;
  place-items: center;
  color: var(--white);
  opacity: 0.8;
}

.lightbox__tool {
  width: 44px;
  height: 44px;
}

.lightbox__tool .icon {
  width: 22px;
  height: 22px;
}

.lightbox__tool:hover,
.lightbox__nav:hover {
  opacity: 1;
}

.lightbox__stage {
  display: grid;
  place-items: center;
  min-height: 0;
  padding: 16px 72px;
  overflow: hidden;
  touch-action: pan-y;
}

/* Video variant ("Watch Demo"): top bar + video, no arrows or caption */
.lightbox--video[open] {
  grid-template-rows: auto minmax(0, 1fr);
}

.lightbox__video {
  width: min(100%, 1280px);
  max-height: calc(100dvh - 110px);
  aspect-ratio: 16 / 9;
  background: var(--black);
}

@media (max-width: 767px) {
  .lightbox--video .lightbox__stage {
    padding-inline: 12px;
  }
}

/* Fits the screen minus the top bar and caption (~180px) */
.lightbox__image {
  max-width: 100%;
  max-height: calc(100dvh - 180px);
  object-fit: contain;
  user-select: none;
}

.lightbox__nav {
  position: absolute;
  top: 50%;
  width: 56px;
  height: 72px;
  margin-top: -36px;
  background: rgb(0 0 0 / 0.35);
}

.lightbox__nav .icon {
  width: 30px;
  height: 30px;
}

.lightbox__nav--prev {
  left: 0;
}

.lightbox__nav--next {
  right: 0;
}

.lightbox__caption {
  padding: 16px 20px 20px;
  background: rgb(0 0 0 / 0.55);
  text-align: center;
}

.lightbox__title {
  font-family: var(--font-display);
  font-size: var(--text-18);
  font-weight: var(--weight-medium);
}

.lightbox__category {
  margin-top: 4px;
  color: var(--on-dark-text);
  font-size: var(--text-14);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}

/* Hidden when the browser can't do full screen (e.g. iPhone) */
.lightbox__tool[hidden] {
  display: none;
}

@media (max-width: 767px) {
  .lightbox__stage {
    padding: 8px;
  }

  .lightbox__image {
    max-height: calc(100dvh - 170px);
  }

  /* Arrows sit over the image on small screens; swipe also works */
  .lightbox__nav {
    width: 44px;
    height: 56px;
    margin-top: -28px;
  }
}


/* --------------------------------------------------------------------------
   LOBO'S TAKE
   One short first-person note from Lobo per page (brief section 4b).
   Loose, no card (Mike, 28-sep-2026): everything centered on the page —
   label on top, avatar in the middle, quote below in two lines
   (main.js › 11 sets the width that splits each quote in two).
   The HTML order stays avatar → label → quote; CSS reorders it.
   Works on light and dark sections (the label turns gold on dark).
   -------------------------------------------------------------------------- */
.lobo-take {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin: var(--space-xl) auto 0;
  text-align: center;
}

.lobo-take__body {
  display: contents;   /* lets label and quote sit above/below the avatar */
}

.lobo-take__label {
  order: 1;
  color: var(--blue-500);
  font-size: var(--text-12);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-widest);
  line-height: var(--leading-snug);
  text-transform: uppercase;
}

[data-nav-tone="dark"] .lobo-take__label {
  color: var(--gold-500);
}

.lobo-take__avatar {
  order: 2;
  width: clamp(88px, 9vw, 120px);
  height: clamp(88px, 9vw, 120px);
  border: 2px solid currentColor;
  border-radius: 50%;
  object-fit: cover;
  object-position: center 30%;
}

.lobo-take__quote {
  order: 3;
  max-width: min(100%, 34em);
  font-family: var(--font-display);
  font-size: var(--text-l);
  font-weight: var(--weight-medium);
  line-height: var(--leading-cozy);
  text-wrap: balance;
}


/* --------------------------------------------------------------------------
   PROCESS STACK — "Follow the Trail" (dark, cards stack as you scroll — Mike, 4-oct-2026)
   Used by: Home, the 7 industry pages and the 4 service pages (Mike, 5-oct-2026).
   Each card sticks near the top and the next one slides over it, leaving the
   top edge of the previous card in view (model: pixelhivestudio.framer.website,
   without its rotation). It is plain CSS (position: sticky), no script.
   Background: the blue texture at 30% over black, fixed to the screen on
   desktop so it drifts against the content like a basic parallax.
   The text on the left is as tall as the finished stack (--card-h + one
   step per extra card), so it lets go at the same moment the third card reaches the top
   and both leave together, clear of Lobo's take below.
   Tweaks: --stack-top (where cards stop), --stack-step (how much of the
   previous card stays visible), --card-h and the gap of .process__cards.
   -------------------------------------------------------------------------- */
.process {
  --stack-top: 120px;
  --stack-step: 36px;
  --stack-count: 3;   /* cards in the stack; service pages set 4 inline */
  --card-h: 26rem;
  padding-block: var(--space-section);
  overflow: clip;
  background: var(--black);
  color: var(--white);
}

.process::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: url("../images/backgrounds/textures/texture-blue.webp") center / cover no-repeat;
  opacity: 0.3;
  pointer-events: none;
}

@media (min-width: 992px) and (hover: hover) and (prefers-reduced-motion: no-preference) {
  .process::after {
    background-attachment: fixed;
  }
}

@media (min-width: 992px) {
  .process__intro {
    min-height: calc(var(--card-h) + var(--stack-step) * (var(--stack-count) - 1));
  }
}

.process__layout {
  row-gap: var(--space-xl);
  align-items: start;
}

.process__intro { grid-column: 1 / 6; }
.process__cards { grid-column: 7 / -1; }
.process .process__take { margin-top: var(--space-2xl); }

.process__intro {
  position: sticky;
  top: var(--stack-top);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-m);
}

.process__title {
  font-size: var(--text-5xl);
  line-height: var(--leading-tight);
}

.process__cards {
  display: grid;
  grid-auto-rows: 1fr;   /* equal slots, so the three cards let go together */
  gap: var(--space-3xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The <li> is an invisible slot: all three stick at the same height and are
   equally tall, so the stack leaves in one piece. The step that keeps the
   previous card's top edge visible is padding inside the slot; the card you
   see is .process-card__body (Mike, 5-oct-2026: card 3 used to slide up over
   the other two before the stack left). */
.process-card {
  position: sticky;
  top: var(--stack-top);
}

.process-card:nth-child(2) { padding-top: var(--stack-step); }
.process-card:nth-child(3) { padding-top: calc(var(--stack-step) * 2); }
.process-card:nth-child(4) { padding-top: calc(var(--stack-step) * 3); }

.process-card__body {
  display: flex;
  flex-direction: column;
  min-height: var(--card-h);
  padding: clamp(1.75rem, 3vw, 3rem);
  border: 1px solid var(--on-dark-line-soft);
  border-radius: var(--radius-card);
  background: var(--blue-850);
}

.process-card__number {
  align-self: flex-end;
  font-family: var(--font-display);
  font-size: var(--text-6xl);
  font-weight: var(--weight-bold);
  line-height: 0.8;
  color: var(--service-design);
}

.process-card__title {
  margin-top: auto;
  padding-top: var(--space-xl);
  font-size: var(--text-3xl);
  line-height: var(--leading-tight);
}

.process-card__text {
  max-width: 32rem;
  margin-top: var(--space-s);
  color: var(--on-dark-text);
  font-size: var(--text-l);
  line-height: var(--leading-normal);
}

@media (max-width: 991px) {
  .process__intro,
  .process__cards { grid-column: 1 / -1; }

  .process__intro {
    position: static;
  }
}

@media (max-width: 767px) {
  .process {
    --stack-top: 96px;
    --stack-step: 20px;
  }

  .process__cards {
    gap: var(--space-2xl);
  }

  .process-card__body {
    min-height: 22rem;
  }
}

/* Reduced motion: plain list, nothing sticks */
@media (prefers-reduced-motion: reduce) {
  .process__cards {
    grid-auto-rows: auto;
  }

  .process-card:nth-child(n) {
    position: static;
    padding-top: 0;
  }
}


/* --------------------------------------------------------------------------
   TEXTURED BACKGROUNDS (faceted polygons, Mike 27-sep-2026)
   Add to any section: class="bg-texture bg-texture--black". The solid color
   underneath shows while the image loads. Paths are relative to this file.
   --texture-opacity (0–1) fades the texture into its solid color by laying a
   veil of that same color on top (e.g. .intro uses 0.5 on black).
   -------------------------------------------------------------------------- */
.bg-texture {
  --texture-veil: linear-gradient(
    color-mix(in srgb, var(--texture-color) calc((1 - var(--texture-opacity, 1)) * 100%), transparent),
    color-mix(in srgb, var(--texture-color) calc((1 - var(--texture-opacity, 1)) * 100%), transparent)
  );
  background-color: var(--texture-color);
  background-image: var(--texture-veil), var(--texture-image);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.bg-texture--black { --texture-color: var(--black); --texture-image: url("../images/backgrounds/textures/texture-black.webp"); }
.bg-texture--white { --texture-color: var(--gray-100); --texture-image: url("../images/backgrounds/textures/texture-white.webp"); }
.bg-texture--blue { --texture-color: var(--blue-500); --texture-image: url("../images/backgrounds/textures/texture-blue.webp"); }
.bg-texture--cyan { --texture-color: var(--cyan-500); --texture-image: url("../images/backgrounds/textures/texture-cyan.webp"); }
.bg-texture--pink { --texture-color: var(--pink-500); --texture-image: url("../images/backgrounds/textures/texture-pink.webp"); }
.bg-texture--orange { --texture-color: var(--gold-500); --texture-image: url("../images/backgrounds/textures/texture-orange.webp"); }

/* --------------------------------------------------------------------------
   CTA STACK (Mike, 28-sep-2026)
   Small label + big button + short note, stacked and centered.
     <div class="cta-stack cta-stack--on-dark">
       <p class="cta-stack__eyebrow">Start a project</p>
       <a class="btn btn--gold cta-stack__btn" href="…">Let’s Book &amp; Talk</a>
       <p class="cta-stack__note">(We don’t bite)</p>
     </div>
   Dark text by default; add .cta-stack--on-dark on dark backgrounds.
   -------------------------------------------------------------------------- */
.cta-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: var(--color-heading);
  text-align: center;
}

.cta-stack--on-dark {
  color: var(--white);
}

.cta-stack__eyebrow {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  line-height: var(--leading-compact);
  text-transform: uppercase;
}

.cta-stack__btn {
  --btn-circle: 46px;
  --btn-inset: 7px;
  --btn-pad: 36px;
  --btn-icon: 22px;
  min-height: 60px;
  padding-block: 14px;
  font-size: var(--text-m);
  letter-spacing: var(--tracking-wide);
}

@media (max-width: 767px) {
  .cta-stack__eyebrow {
    font-size: var(--text-20);
  }

  .cta-stack__btn {
    --btn-circle: 38px;
    --btn-inset: 6px;
    --btn-pad: 26px;
    --btn-icon: 18px;
    min-height: 50px;
    padding-block: 10px;
    font-size: var(--text-16);
  }
}

.cta-stack__note {
  font-size: var(--text-14);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   TRUST BADGE (Mike, 28-sep-2026)
   Short line of social proof + overlapping round photos.
   Dark text by default; add .trust-badge--on-dark on dark backgrounds.
   -------------------------------------------------------------------------- */
.trust-badge {
  display: inline-flex;
  align-items: center;
  gap: 18px;
  color: var(--color-heading);
}

.trust-badge--on-dark {
  color: var(--white);
}

.trust-badge__text {
  font-size: var(--text-14);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wider);
  line-height: var(--leading-cozy);
  text-transform: uppercase;
}

.trust-badge__text strong {
  display: block;
  font-weight: var(--weight-bold);
}

.trust-badge__faces {
  display: flex;
  margin: 0;
  padding: 0;
  list-style: none;
}

.trust-badge__faces li + li {
  margin-left: -14px;
}

.trust-badge__faces img {
  display: block;
  width: 48px;
  height: 48px;
  border: 2px solid var(--white);
  border-radius: var(--radius-pill);
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   ORBIT CAROUSEL (Mike, 28-sep-2026; based on mondragon6.framer.website/studio)
   Square cards travel slowly right to left around an invisible ring: the one
   in the middle is the biggest, the others shrink toward the edges and rise
   or drop along a soft wave. Approved exception to the "no animations" rule.
     <div class="orbit" data-orbit>
       <ul class="orbit__track" role="list">
         <li class="orbit__card"><img class="orbit__image" src="…" alt="…"></li>
       </ul>
     </div>
   main.js › 10 positions the cards (adds .is-live). Without JavaScript, or
   with "reduce motion", it stays a plain row that scrolls sideways by hand.
   Hover: the card lightens a little. It can be grabbed and moved to both
   sides (mouse or finger).
   -------------------------------------------------------------------------- */
.orbit__track {
  display: flex;
  gap: var(--grid-gap);
  overflow-x: auto;
  padding-inline: var(--grid-margin);
  scroll-snap-type: x mandatory;
}

.orbit__card {
  flex: 0 0 clamp(220px, 28vw, 380px);
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: var(--radius-card);
  background: var(--blue-900);
  scroll-snap-align: center;
}

.orbit__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter 0.35s ease;
}

.orbit__card:hover .orbit__image {
  filter: brightness(1.12);
}

/* Live mode (JavaScript on): cards are placed one by one with transforms */
.orbit.is-live {
  position: relative;
  height: var(--orbit-height, 560px);
  overflow: hidden;
  cursor: grab;
  touch-action: pan-y;   /* sideways swipes move the carousel, vertical ones scroll the page */
  user-select: none;
  -webkit-user-select: none;
}

.orbit.is-dragging {
  cursor: grabbing;
}

.orbit.is-live .orbit__track {
  position: absolute;
  inset: 0;
  display: block;
  overflow: visible;
  padding: 0;
}

.orbit.is-live .orbit__card {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--orbit-card, 320px);
  height: var(--orbit-card, 320px);
  margin: calc(var(--orbit-card, 320px) / -2) 0 0 calc(var(--orbit-card, 320px) / -2);
  will-change: transform, opacity;
}

/* --------------------------------------------------------------------------
   HEADLINE CAPS
   Short headings in uppercase Clash Grotesk Semibold, inspired by
   operatorx.framer.website. Only for headings of ~30 characters or less.
   Optional second part in brand color, on its own line:
     <h2 class="headline-caps">We know brands <span class="headline-caps__accent">get complicated.</span></h2>
   Blue on light backgrounds, gold on dark ones (add .headline-caps--on-dark).
   Uppercase comes from CSS, so screen readers read the sentence normally.
   -------------------------------------------------------------------------- */
:is(h1, h2, h3).headline-caps {
  --headline-accent: var(--blue-500);
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-none);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}

:is(h1, h2, h3).headline-caps--on-dark {
  --headline-accent: var(--gold-500);
}

.headline-caps__accent {
  display: block;
  color: var(--headline-accent);
}


/* --------------------------------------------------------------------------
   SLOT TEXT — horizontal (approved by Mike, 28-sep-2026)
   Each letter turns sideways like a small cube and lands on the same
   letter, one after another from left to right. Plays once on view.
   Opt-in: add data-slot-text to a heading (main.js does the rest, only
   when motion is allowed).
   Structure made by main.js, per letter:
     <span class="slot__char">
       <span class="slot__face">A</span><span class="slot__face">A</span>
     </span>
   -------------------------------------------------------------------------- */
.slot__word {
  display: inline-block;
  white-space: nowrap;
}

.slot__char {
  position: relative;
  display: inline-block;
}

.slot__face {
  display: inline-block;
  /* Pivot sits behind the letter, so the two faces turn like a cube */
  transform-origin: 50% 50% -0.4em;
  backface-visibility: hidden;
}

/* The copy sits on top of the original, hidden until it turns in */
.slot__face:last-child {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.is-rolling .slot__face {
  animation-duration: 0.85s;
  animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
  animation-fill-mode: both;
  animation-delay: calc(var(--slot-i, 0) * 60ms);
}

.is-rolling .slot__face:first-child {
  animation-name: slot-turn-out;
}

.is-rolling .slot__face:last-child {
  animation-name: slot-turn-in;
}

@keyframes slot-turn-out {
  from { transform: perspective(600px) rotateY(0);     opacity: 1; }
  to   { transform: perspective(600px) rotateY(90deg); opacity: 0; }
}

@keyframes slot-turn-in {
  from { transform: perspective(600px) rotateY(-90deg); opacity: 0; }
  to   { transform: perspective(600px) rotateY(0);      opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .is-rolling .slot__face {
    animation: none;
  }
}

/* --------------------------------------------------------------------------
   COUNTER REELS (Mike, 7-oct-2026)
   Model: the stats in the hero of neuralflowtemplate.webflow.io (home v1).
   main.js › 18 turns every digit of the figures (.hero-stat__value,
   .stat__value, .ind-stat__value) into a vertical reel: 0–9 and back to the
   same digit, so one full turn lands on the real number. Without JavaScript
   or with "reduce motion" the figures stay as plain text and nothing here
   applies. The ghost digit keeps the exact width and height of the final
   number, so the layout never moves.
   -------------------------------------------------------------------------- */
.counter {
  user-select: none;
}

.counter__digit {
  position: relative;
  display: inline-block;
  vertical-align: top;     /* an inline-block that clips sits on its bottom edge by default */
  overflow-y: clip;        /* hide the other digits; sideways stays open so wide digits are not cut */
}

.counter__ghost {
  visibility: hidden;
}

.counter__reel {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  will-change: transform;
}

.counter__reel > span {
  display: block;
  flex: none;
}

/* --------------------------------------------------------------------------
   IMAGE REVEAL + PARALLAX (Mike, 7-oct-2026)
   Model: "Top Appear" and "Parallax Image" on luzen-temlis.webflow.io.
   1) Reveal: as the image scrolls into view the frame opens from the top down
      (the original slides a curtain off the photo) while the photo zooms out,
      2 s, easeOutQuart.
   2) Parallax: the photo is a little bigger than its frame (--reveal-overscan,
      1.2 = 20% bigger) and keeps drifting inside the frame while you scroll,
      moving down while the page moves up, so it travels slower than the page.
   Markup: the frame is a wrapper that carries the layout classes (size, grid
   column, aspect ratio) and the photo sits inside it:
     <div class="reveal service__art"><img src="…" alt="…" width="…" height="…"></div>
   Set where the photo is cropped with --reveal-position (default centered) and
   how much it drifts with --reveal-overscan (1 = no drift).
   main.js › 19 adds .is-armed to every .reveal (hidden, photo enlarged), then
   .is-revealed when it enters the screen (once), and moves the photo with the
   scroll through the "translate" property. The zoom uses the "scale" property,
   so the two never fight. Without JavaScript or with "reduce motion" the
   photo is simply there, uncropped. Used on: homepage service art, service
   gallery + "Who it's for", industry "What We Can Build" photo.
   -------------------------------------------------------------------------- */
.reveal {
  position: relative;
  overflow: hidden;
}

.reveal > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--reveal-position, 50% 50%);
}

@media (prefers-reduced-motion: no-preference) {
  .reveal.is-armed {
    clip-path: inset(0 0 100% 0);
  }

  /* Enlarged a bit so it has room to drift (transform), plus the opening zoom (scale) */
  .reveal.is-armed > img {
    transform: scale(var(--reveal-overscan, 1.2));
    scale: 1.4;
    will-change: translate, scale;
  }

  .reveal.is-armed.is-revealed {
    clip-path: inset(0);
    transition: clip-path 2000ms cubic-bezier(0.25, 1, 0.5, 1) var(--reveal-delay, 0ms);
  }

  .reveal.is-armed.is-revealed > img {
    scale: 1;
    transition: scale 2000ms cubic-bezier(0.25, 1, 0.5, 1) var(--reveal-delay, 0ms);
  }
}


/* --------------------------------------------------------------------------
   FADE IN (Mike, 7-oct-2026)
   A quiet entrance for small groups: call-to-action buttons, labels and a
   few sets of cards. Each piece fades in and rises a few pixels the first
   time it scrolls into view; pieces of the same group follow one another.
   main.js › 26 decides which elements get it (list FADE_GROUPS), adds
   .fade-in, and then .is-in with --fade-delay. Nothing to add in the HTML.
   Not used where something else already moves (pictures with IMAGE REVEAL,
   slot-text headings, counters, stacked cards, review cards, logo grid).
   Without JavaScript or with "reduce motion" everything is simply there.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .fade-in:not(.is-in) {
    opacity: 0;
  }

  .fade-in.is-in {
    animation: fade-in 0.7s cubic-bezier(0.22, 1, 0.36, 1) var(--fade-delay, 0ms) backwards;
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
    translate: 0 var(--fade-rise, 18px);
  }
}
