/*
Theme Name: Flyboy Creative Lab
Theme URI:
Author: Flyboy Creative Lab
Author URI:
Description: Custom WordPress theme for Flyboy Creative Lab -- a cinematic, bilingual (ES/EN) creative-agency theme built with vanilla HTML/CSS/JS and GSAP/ScrollTrigger.
Version: 1.0.1
Requires at least: 5.9
Requires PHP: 7.4
Text Domain: flyboy-creative-lab
License: Proprietary -- All Rights Reserved

This stylesheet is the theme's real, complete CSS (unchanged from the
site's own development source below this header). WordPress reads only
the comment block above; nothing else in this file is theme metadata.
*/
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:root {
  --fb-black: #0b0808;
  --fb-white: #f4f2ed;
  --fb-red: #f22a12;
  --fb-orange: #ff6a00;
  --fb-gray: #a7a7a7;

  /* Global typographic system: Myriad Pro, used deliberately across three
     weights (Light/Regular/Bold) for editorial hierarchy -- not a blanket
     find-and-replace. No licensed Myriad Pro webfont files exist in this
     project yet (checked assets/, no .woff/.woff2/.ttf/.otf anywhere), so
     this stack relies on a locally installed copy for local preview and
     falls back to Arial/sans-serif everywhere else. See FILES CHANGED
     report: production needs the actual licensed WOFF2/WOFF files added
     via @font-face before this renders as Myriad Pro for real visitors. */
  --font-primary: 'Myriad Pro', 'Myriad Pro Regular', Arial, sans-serif;
  --font: var(--font-primary);
  --weight-light: 300;
  --weight-regular: 400;
  --weight-bold: 700;
  --tracking-tight: -0.04em;
  --tracking-tighter: -0.06em;
  --tracking-label: 0.14em;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  --works-gap: 5rem;
  --works-edge: 5rem;
  --portfolio-rail-width: clamp(260px, 19vw, 340px);
  --works-lead: clamp(40px, 5vw, 90px);

}

html {
  font-size: 16px;
  scroll-behavior: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--font);
  background: var(--fb-black);
  color: var(--fb-white);
  overflow-x: hidden;
  line-height: 1.5;
  position: relative;
}

body.is-loading {
  overflow: hidden;
}

/* Global grain atmosphere -- the approved technique: a small tile of true
   random monochrome noise, regenerated on an interval (see mountGrain() in
   main.js) and applied as a repeating background-image, exactly as in
   grain-background-demo.html. Sits BEHIND all site content (z-index 1 vs.
   .site-content's z-index 2) so it can never paint over cards, copy, or
   media. Visibility is controlled entirely by the .is-hidden class
   (toggled by an IntersectionObserver watching Hero and Portfolio) -- the
   element is always mounted and always regenerating; only its opacity
   changes, so there is never a flash or a destroy/recreate cycle. Every
   section uses background: transparent, so this layer blends directly
   against body's near-black --fb-black. mix-blend-mode: screen (rather
   than overlay) is deliberate: overlay's math collapses toward the
   backdrop color as it approaches black, which made the grain almost
   imperceptible on this site's dark sections; screen keeps the noise
   visible there while still doing nothing over already-bright pixels. */
.flyboy-global-grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
  background-repeat: repeat;
  image-rendering: pixelated;
  opacity: 0.07;
  mix-blend-mode: screen;
  transition: opacity 0.45s ease;
}

.flyboy-global-grain.is-hidden {
  opacity: 0;
}

.site-content {
  position: relative;
  z-index: 2;
}

@media (prefers-reduced-motion: reduce) {
  .flyboy-global-grain {
    display: none;
  }
}

a {
  color: inherit;
  text-decoration: none;
}

em {
  font-style: italic;
  color: var(--fb-gray);
}

img,
video {
  display: block;
  max-width: 100%;
}

/* ------------------------------------------------------------------ */
/* Intro Loader                                                        */
/* ------------------------------------------------------------------ */

.intro-loader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--fb-black);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.75rem;
  pointer-events: all;
}

/* Loader's own dedicated grain -- the SAME mountGrain() technique and dark
   config as the global atmosphere, but a separate instance scoped inside
   the loader. It cannot simply reveal the real global element underneath:
   the loader's own backdrop must stay opaque enough that Hero never bleeds
   through, so it needs its own copy of the same visual system instead. */
.intro-loader__grain {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  background-repeat: repeat;
  image-rendering: pixelated;
  opacity: 0.07;
  mix-blend-mode: screen;
}

.intro-loader__logo-stage {
  position: relative;
  z-index: 1;
  width: min(170px, 32vw);
  aspect-ratio: 1380.52 / 1446.26;
}

.intro-loader__logo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  filter: none;
  mix-blend-mode: normal;
  backdrop-filter: none;
}

.intro-loader__logo--ghost {
  opacity: 0;
  mix-blend-mode: screen;
  pointer-events: none;
  filter: brightness(0) saturate(100%) invert(21%) sepia(94%) saturate(6800%) hue-rotate(2deg) brightness(1.05) contrast(1.05);
}

.intro-loader__scanline {
  position: absolute;
  left: -15%;
  width: 130%;
  height: 2px;
  top: 40%;
  background: var(--fb-white);
  opacity: 0;
  pointer-events: none;
}

.intro-loader__status {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 1rem;
  opacity: 0;
  font-family: monospace;
}

.intro-loader__status-text {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--fb-gray);
}

.intro-loader__pct {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.05em;
  font-variant-numeric: tabular-nums;
  color: var(--fb-white);
}

.intro-loader__bar-wrap {
  position: relative;
  z-index: 1;
  width: min(220px, 50vw);
  height: 1px;
  background: rgba(244, 242, 237, 0.15);
  opacity: 0;
}

.intro-loader__bar {
  width: 0%;
  height: 100%;
  background: var(--fb-white);
}

/* ------------------------------------------------------------------ */
/* Nav                                                                  */
/* ------------------------------------------------------------------ */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.5rem 3rem;
  z-index: 100;
}

/* Global, breakpoint-independent: .nav__backdrop must never sit in flex flow.
   .nav has 3 children (backdrop, logo, links); left in flow, a zero-width
   backdrop is still counted as the FIRST item, which makes justify-content:
   space-between treat .nav__logo as the *middle* item and center it in the
   remaining space instead of pinning it to the left edge -- worse the
   narrower .nav__links gets relative to the viewport (i.e. worse on exactly
   the desktop/adaptive widths this was reported on). Only the visual glass
   background differs per breakpoint (mobile-only, added below); the layout
   fix itself applies everywhere. */
.nav__backdrop {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

/* Isolated from .nav__links' difference blend below -- mix-blend-mode on an
   ancestor composites its whole rendered subtree as one unit, so a child
   can't opt out of it by setting isolation on itself. The blend is scoped
   to .nav__links only; the logo gets its own explicit normal/isolated
   stacking context so it renders in its true SVG colors always. */
.nav__logo {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  mix-blend-mode: normal;
  filter: none;
  backdrop-filter: none;
  isolation: isolate;
}

.nav__logo-img {
  width: 106px;
  height: auto;
  transition: width 0.38s var(--ease-out);
  opacity: 1;
  mix-blend-mode: normal;
  filter: none;
  backdrop-filter: none;
  isolation: isolate;
}

/* Compact header mode while the Portfolio section is in view -- toggled by
   an IntersectionObserver in initPortfolio(), fully independent of the
   horizontal-scroll ScrollTrigger. */
body.portfolio-active .nav__logo-img {
  width: 46px;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 2.5rem;
  font-size: 0.875rem;
  font-weight: var(--weight-regular);
  letter-spacing: 0.02em;
  mix-blend-mode: difference;
}

.nav__links a {
  position: relative;
  transition: opacity 0.3s ease;
}

.nav__links a:hover {
  opacity: 0.6;
}

.nav__cta {
  font-weight: var(--weight-bold);
  padding: 0.55rem 1.5rem;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 100px;
  transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
  box-shadow: 0 0 16px rgba(242, 42, 18, 0.16);
}

.nav__cta:hover {
  background: var(--fb-white);
  color: var(--fb-black);
  border-color: var(--fb-white);
  opacity: 1 !important;
  box-shadow: 0 0 22px rgba(242, 42, 18, 0.3);
}

/* Hamburger for the PROYECTOS/SERVICIOS links that .nav__links hides at
   mobile widths -- desktop/tablet never show this, mobile media query
   below switches it to display:flex. 44px tap target per touch-target
   guidance, even though the visible glyph is much smaller. */
.nav__menu-toggle {
  display: none;
  appearance: none;
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
  /* <button> gets a UA-default color that does not inherit like normal
     text -- without this, background:currentColor on the bars below
     resolves to black instead of the surrounding white nav text,
     rendering invisible under .nav__links' mix-blend-mode:difference. */
  color: inherit;
}

.nav__menu-toggle span {
  display: block;
  width: 18px;
  height: 1.5px;
  background: currentColor;
  transition: transform 0.3s var(--ease-out), opacity 0.3s ease;
}

.nav__menu-toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(6.5px) rotate(45deg);
}

.nav__menu-toggle[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}

.nav__menu-toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-6.5px) rotate(-45deg);
}

/* Unconditional (not just [hidden]) so desktop/tablet can never show this
   regardless of the hidden attribute's state -- the mobile-only rule below
   uses :not([hidden]), whose specificity (0,0,2,0) already beats this
   (0,0,1,0) source-order-independently once it's inside the mobile query. */
.nav__mobile-menu {
  display: none;
}

/* ES / EN language selector -- lives inside .nav__links so it inherits the
   same mix-blend-mode: difference treatment as the other nav links. Plain
   <button>s (not <a>), so the mobile rule ".nav__links a:not(.nav__cta)
   { display: none; }" below never hides it -- it stays visible on mobile
   next to the HABLEMOS CTA without needing its own breakpoint override. */
.nav__lang {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.nav__lang-btn {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  cursor: pointer;
  opacity: 0.45;
  transition: opacity 0.3s ease;
}

.nav__lang-btn:hover {
  opacity: 0.8;
}

.nav__lang-btn.is-active {
  opacity: 1;
  font-weight: var(--weight-bold);
}

.nav__lang-sep {
  font-size: 0.8125rem;
  opacity: 0.3;
}

/* ------------------------------------------------------------------ */
/* Hero                                                                 */
/* ------------------------------------------------------------------ */

.hero {
  position: relative;
  width: 100%;
  height: 250vh;
}

.hero__pin {
  position: relative;
  width: 100%;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.hero__video {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  object-fit: cover;
  z-index: 0;
  will-change: transform;
  pointer-events: none;
}

.hero__overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background:
    linear-gradient(to bottom, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.2) 40%, rgba(0, 0, 0, 0.2) 60%, rgba(0, 0, 0, 0.8) 100%);
  z-index: 1;
}

.hero__fade-out {
  display: none;
}

.hero__content {
  position: relative;
  z-index: 2;
  text-align: center;
  max-width: 900px;
  padding: 0 2rem;
}

.hero__tag {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fb-gray);
  margin-bottom: 1.5rem;
  opacity: 0;
}

.hero__heading {
  display: flex;
  flex-direction: column;
  gap: 0.02em;
  font-size: clamp(2.2rem, 5.5vw, 4.75rem);
  font-weight: var(--weight-bold);
  line-height: 1.05;
  letter-spacing: var(--tracking-tighter);
  margin-bottom: 1.5rem;
}

.hero__line-mask {
  display: block;
  overflow: hidden;
}

.hero__line {
  display: block;
  transform: translateY(110%);
  opacity: 0;
}

/* Real Light-weight typography instead of a transparent/stroke outline --
   more readable and matches the site's Bold/Regular/Light system directly
   (see --weight-light) rather than relying on a separate visual trick. */
.hero__line--outline {
  font-weight: var(--weight-light);
  color: var(--fb-white);
}

.hero__accent-dot {
  color: var(--fb-red);
}

.hero__sub {
  font-size: 1rem;
  color: var(--fb-gray);
  max-width: 580px;
  margin: 0 auto 2.5rem;
  line-height: 1.6;
  text-align: justify;
  text-align-last: center;
  opacity: 0;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.9rem 2.2rem;
  font-size: 0.875rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.03em;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 100px;
  transition: all 0.4s var(--ease-out);
  opacity: 0;
  cursor: pointer;
  background: transparent;
  color: var(--fb-white);
}

.btn:hover {
  background: var(--fb-white);
  color: var(--fb-black);
  border-color: var(--fb-white);
  gap: 0.85rem;
}

.btn__arrow {
  transition: transform 0.4s var(--ease-out);
}

.btn:hover .btn__arrow {
  transform: translateX(4px);
}

.hero__scroll-indicator {
  position: absolute;
  bottom: 2.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  opacity: 0;
}

.hero__scroll-indicator span {
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--fb-gray);
}

.hero__scroll-line {
  width: 1px;
  height: 40px;
  background: rgba(255, 255, 255, 0.2);
  position: relative;
  overflow: hidden;
}

.hero__scroll-line::after {
  content: '';
  position: absolute;
  top: -100%;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--fb-white);
  animation: scrollLine 2s ease-in-out infinite;
}

@keyframes scrollLine {
  0% { top: -100%; }
  50% { top: 100%; }
  100% { top: 100%; }
}

/* ------------------------------------------------------------------ */
/* Works / Portfolio (horizontal scroll)                                */
/* Direct reconstruction of /portfolio-reference #works-* + .work-item  */
/* markup and values, re-skinned with the Flyboy palette. Fixed-rail    */
/* clipping: .works__viewport is the ONLY element that clips -- it is   */
/* offset from the left by --portfolio-rail-width and hides anything    */
/* still under the rail via overflow:hidden, not z-index alone.         */
/* ------------------------------------------------------------------ */

.works {
  position: relative;
  background: transparent;
  overflow: hidden;
}

.works__container {
  position: relative;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

.works__fixed-ui {
  position: absolute;
  top: 138px;
  left: clamp(30px, 2.5vw, 48px);
  width: clamp(220px, 16vw, 245px);
  height: auto;
  max-height: 520px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 0;
  pointer-events: none;
}

.works__fixed-ui > * {
  pointer-events: auto;
}

.works__heading-eyebrow {
  display: block;
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(244, 242, 237, 0.55);
  margin-bottom: 1rem;
}

.works__heading-title {
  font-size: clamp(2.125rem, 3vw, 3rem);
  font-weight: var(--weight-bold);
  line-height: 0.92;
  letter-spacing: -0.035em;
}

.works__heading-line {
  display: block;
}

.works__heading-line--fill {
  color: var(--fb-white);
}

/* Editorial counterpoint to the bold sans line above: a light italic serif
   (Fraunces, see index.html <head>) in solid --fb-gray instead of the
   previous heavy stroke-outline treatment -- same two-line composition,
   but the contrast now comes from real typographic variety (weight, style,
   family) rather than a fill/outline trick on the same face. */
.works__heading-line--outline {
  font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.005em;
  line-height: 1.05;
  color: var(--fb-gray);
  margin-top: 0.1em;
}

.works__categories {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.85rem;
  margin-top: 2rem;
}

.works__category {
  appearance: none;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: 0.75rem;
  font-weight: var(--weight-regular);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: rgba(167, 167, 167, 0.55);
  cursor: pointer;
  text-align: left;
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  transition: color 0.3s ease;
}

.works__category::before {
  content: '';
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--fb-red);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.works__category:hover {
  color: rgba(244, 242, 237, 0.85);
}

.works__category.is-active {
  color: var(--fb-white);
}

.works__category.is-active::before {
  opacity: 1;
  transform: scale(1);
}

.works__viewport {
  position: absolute;
  left: var(--portfolio-rail-width);
  right: 0;
  top: 0;
  bottom: 0;
  overflow: hidden;
}

.works__wrapper {
  display: flex;
  align-items: center;
  height: 100%;
  gap: var(--works-gap);
  padding: 0 var(--works-edge);
  padding-left: var(--works-lead);
  will-change: transform;
}

.work-item {
  position: relative;
  flex-shrink: 0;
  width: 80vw;
  /* 66vh, not the old 60vh: a true 16:9 .work-item__media (up from the old
     height:60%) needs more room at this card width than 60vh reliably
     gives on real desktop viewport heights -- media was being flex-shrunk
     well below 16:9 to make everything fit. */
  height: 66vh;
  cursor: pointer;
}

@media (min-width: 768px) {
  .work-item {
    width: 600px;
  }
}

.work-item__link {
  display: block;
  position: absolute;
  inset: 0;
}

.work-item__back {
  position: absolute;
  inset: 0;
  background: var(--card-back);
  border: 1px solid var(--card-border);
  transform: rotate(var(--rotate));
  transition: transform 0.5s var(--ease-out), box-shadow 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.work-item:hover .work-item__back,
.work-item:focus-within .work-item__back,
.work-item.is-active .work-item__back {
  transform: rotate(0deg);
  box-shadow: 0 0 26px rgba(242, 42, 18, 0.12);
}

.work-item__card {
  position: absolute;
  inset: 0;
  background-color: var(--card-bg);
  color: var(--card-fg);
  border: 1px solid var(--card-border);
  /* 1.75rem, not the old 2rem -- a small, deliberate reduction so the now
     tag-free cover (100% of this inner width) reads slightly larger,
     without touching the card's own outer size or structure. */
  padding: 1.75rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  transform: translateY(0);
  transition: transform 0.5s var(--ease-out), box-shadow 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.work-item:hover .work-item__card,
.work-item:focus-within .work-item__card,
.work-item.is-active .work-item__card {
  transform: translateY(-0.5rem);
  box-shadow: 0 0 32px rgba(242, 42, 18, 0.18), 0 0 70px rgba(242, 42, 18, 0.09), inset 0 0 30px rgba(242, 42, 18, 0.05);
}

.work-item__media {
  position: relative;
  width: 100%;
  flex-shrink: 0;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--card-muted);
  margin-bottom: 1rem;
}

.work-item__image,
.work-item__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) brightness(0.84);
  transform: scale(1.1);
  transition: filter 0.7s ease, transform 0.7s ease;
}

.work-item:hover .work-item__image,
.work-item:hover .work-item__video,
.work-item:focus-within .work-item__image,
.work-item:focus-within .work-item__video,
.work-item.is-active .work-item__image,
.work-item.is-active .work-item__video {
  filter: grayscale(0) brightness(1);
  transform: scale(1);
}

/* Touch devices have no hover -- reveal color by default rather than
   leaving covers permanently monochrome (no new ScrollTrigger/observer,
   pure CSS, zero scroll-performance cost). */
@media (hover: none) {
  .work-item__image,
  .work-item__video {
    filter: grayscale(0) brightness(1);
  }
}

.work-item__placeholder {
  width: 100%;
  height: 100%;
}

/* Category overlay intentionally removed from the visible card (still
   rendered into the DOM by renderWorkItem() with its category text and
   item.dataset.category -- filtering reads that dataset, not this
   element's visibility -- so filters keep working untouched). display:none
   drops it from layout entirely: no text, no border, no line, no
   background, no reserved space, on any breakpoint. */
.work-item__tag {
  display: none;
}

.work-item__title {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  margin-bottom: 0.5rem;
}

.work-item__desc {
  font-family: monospace;
  font-size: 0.8125rem;
  color: var(--card-fg);
  opacity: 0.65;
  line-height: 1.5;
}

.work-item__footer {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  border-top: 1px solid var(--card-border);
  padding-top: 1rem;
}

.work-item__number {
  font-size: 2rem;
  font-weight: var(--weight-bold);
  opacity: 0.12;
  transition: opacity 0.5s ease;
}

.work-item:hover .work-item__number,
.work-item:focus-within .work-item__number,
.work-item.is-active .work-item__number {
  opacity: 1;
}

.work-item__arrow {
  font-size: 1.5rem;
  display: inline-block;
  transition: transform 0.3s var(--ease-out), color 0.4s ease;
}

.work-item:hover .work-item__arrow,
.work-item:focus-within .work-item__arrow,
.work-item.is-active .work-item__arrow {
  transform: translate(4px, -4px);
  color: var(--fb-red);
}

/* Micro-label -- sits in the card's own empty bottom padding, below the
   footer, so it never collides with the description text above it. */
.work-item__card::after {
  content: attr(data-micro-label);
  position: absolute;
  left: 1.75rem;
  bottom: 0.6rem;
  font-family: monospace;
  font-size: 0.625rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--card-fg);
  opacity: 0.28;
  pointer-events: none;
}

/* Mobile card composition: the desktop card relies on a fixed .work-item
   height (66vh) + justify-content:space-between on .work-item__card to
   distribute media/body/footer -- on short content that leaves large,
   unintentional empty gaps (exactly the "floating in a big black
   rectangle" complaint). Below 768px the card switches to natural,
   content-driven height with explicit small gaps instead: .work-item__link
   and .work-item__card drop out of the position:absolute/inset:0 stack
   (which requires .work-item's fixed height to mean anything) and become
   normal flow, so .work-item's own height simply becomes "whatever the
   content needs." .work-item__back is a hover-only decorative panel --
   hover never fires on touch (see the existing prefers:hover:none rule
   above) so it's just hidden rather than fought into this flow. */
@media (max-width: 768px) {
  .work-item {
    height: auto;
  }

  .work-item__link {
    position: relative;
    inset: auto;
    display: block;
  }

  .work-item__back {
    display: none;
  }

  .work-item__card {
    position: relative;
    inset: auto;
    width: 100%;
    justify-content: flex-start;
    /* Sides/top slimmer than desktop's 1.75rem so the cover (100% of this
       inner width) reads as ~87% of the outer card -- within the
       requested 85-92% range. Bottom kept taller to leave room for the
       ::after micro-label without it colliding with the footer row. */
    padding: 1.25rem 1.25rem 2.25rem;
  }

  .work-item__media {
    margin-bottom: 2rem;
  }

  .work-item__body {
    margin-bottom: 1.75rem;
  }

  .work-item__title {
    margin-bottom: 0.875rem;
  }

  .work-item__card::after {
    left: 1.25rem;
  }
}

/* ---- Finish system: 5 reusable dark-editorial variants, CSS-variable   */
/* driven. All five now share the same Space Black base + Fly White text  */
/* + restrained inactive border -- the finish only changes the exact dark */
/* tone and its one distinguishing decorative accent. Active/hover state  */
/* (Signal Red border + corner brackets + full-color cover) is uniform    */
/* across all five, defined once above, not per finish.                  */

.work-item--finish-mission {
  --card-back: #0b0808;
  --card-bg: #0b0808;
  --card-fg: var(--fb-white);
  --card-muted: rgba(244, 242, 237, 0.06);
  --card-border: rgba(244, 242, 237, 0.18);
  --tag-border: rgba(244, 242, 237, 0.16);
}

.work-item--finish-mission .work-item__card::before {
  content: '';
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--fb-red);
}

.work-item--finish-graphite {
  --card-back: #171414;
  --card-bg: #171414;
  --card-fg: var(--fb-white);
  --card-muted: rgba(244, 242, 237, 0.06);
  --card-border: rgba(244, 242, 237, 0.18);
  --tag-border: rgba(244, 242, 237, 0.16);
}

.work-item--finish-graphite .work-item__card::before {
  content: '';
  position: absolute;
  inset: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.06);
  pointer-events: none;
}

.work-item--finish-cinematic {
  --card-back: #121010;
  --card-bg: #121010;
  --card-fg: var(--fb-white);
  --card-muted: rgba(244, 242, 237, 0.06);
  --card-border: rgba(244, 242, 237, 0.18);
  --tag-border: rgba(244, 242, 237, 0.16);
}

.work-item--finish-cinematic .work-item__media::before,
.work-item--finish-cinematic .work-item__media::after {
  content: '';
  position: absolute;
  width: 18px;
  height: 18px;
  border: 1px solid var(--fb-red);
  z-index: 1;
  pointer-events: none;
}

.work-item--finish-cinematic .work-item__media::before {
  top: 0.5rem;
  left: 0.5rem;
  border-right: none;
  border-bottom: none;
}

.work-item--finish-cinematic .work-item__media::after {
  bottom: 0.5rem;
  right: 0.5rem;
  border-left: none;
  border-top: none;
}

.work-item--finish-signal {
  --card-back: #171414;
  --card-bg: #171414;
  --card-fg: var(--fb-white);
  --card-muted: rgba(244, 242, 237, 0.06);
  --card-border: rgba(244, 242, 237, 0.18);
  --tag-border: rgba(244, 242, 237, 0.16);
}

.work-item--finish-signal .work-item__card::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(244, 242, 237, 0.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(244, 242, 237, 0.025) 1px, transparent 1px);
  background-size: 24px 24px;
  pointer-events: none;
}

.work-item--finish-duotone {
  --card-back: #0b0808;
  --card-bg: #0b0808;
  --card-fg: var(--fb-white);
  --card-muted: rgba(244, 242, 237, 0.06);
  --card-border: rgba(244, 242, 237, 0.18);
  --tag-border: rgba(244, 242, 237, 0.16);
}

.work-item--finish-duotone .work-item__card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 3px;
  height: 100%;
  background: linear-gradient(to bottom, var(--fb-orange), var(--fb-red));
}

.works__end {
  flex-shrink: 0;
  width: 20vw;
  min-width: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.works__end-link {
  width: 8rem;
  height: 8rem;
  border-radius: 50%;
  border: 1px solid var(--fb-white);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: monospace;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  transition: background 0.3s ease, color 0.3s ease;
}

.works__end-link:hover {
  background: var(--fb-white);
  color: var(--fb-black);
}

/* Desktop-only "show 6, then reveal the rest" affordance -- appended as
   the next item in the horizontal track in place of .works__end (which
   still appears once the full set is shown, whether via expansion or a
   specific filter). Sized/positioned like .works__end so it reads as
   part of the same row rather than a foreign element. */
.works__view-all {
  flex-shrink: 0;
  width: 20vw;
  min-width: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.works__view-all-btn {
  appearance: none;
  cursor: pointer;
  font-family: inherit;
  background: transparent;
  border: 1px solid var(--fb-white);
  border-radius: 100px;
  padding: 1rem 2rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--fb-white);
  white-space: nowrap;
  transition: background 0.3s ease, color 0.3s ease;
}

.works__view-all-btn:hover {
  background: var(--fb-white);
  color: var(--fb-black);
}

/* ------------------------------------------------------------------ */
/* Shared eyebrow (Studio / Capabilities / Process / Lab / Business Scan /
   Contact)                                                              */
/* ------------------------------------------------------------------ */

.eyebrow {
  display: flex;
  align-items: center;
  gap: 1rem;
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--fb-gray);
  margin-bottom: 2.5rem;
}

.label-line {
  display: block;
  width: 40px;
  height: 1px;
  background: var(--fb-gray);
}

/* ------------------------------------------------------------------ */
/* Studio                                                               */
/* ------------------------------------------------------------------ */

.studio {
  position: relative;
  z-index: 2;
  padding: 4rem 3rem 7rem;
  background: transparent;
  /* overflow must stay visible here: any ancestor with overflow other than
     visible breaks position:sticky on .studio-sticky below. */
}

/* Post-pinned-scroll summary strip: same 6 disciplines the narrative above
   just walked through, as a plain thin-divider row (section 8 spec). */
.studio__labels {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem 2rem;
  max-width: 1400px;
  margin: 4rem auto 0;
  padding-top: 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.studio__label {
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fb-gray);
  display: inline-block;
  opacity: 0;
  transform: translateY(8px);
  transition: color 0.3s ease;
}

/* Hidden by default (desktop's flat row doesn't use it) -- only shown in
   the mobile redesign below. */
.studio__labels-meta {
  display: none;
}

/* ------------------------------------------------------------------ */
/* Studio pinned visual narrative (6 discipline states)                */
/* ------------------------------------------------------------------ */

.studio-scroll {
  position: relative;
  height: 600vh;
  margin-top: 1rem;
}

.studio-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  align-items: center;
  gap: 4rem;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 3rem;
}

.studio-copy {
  position: relative;
  height: 16rem;
}

.studio-copy__state {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.25rem;
  opacity: 0;
  will-change: transform, opacity;
}

.studio-copy__eyebrow {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fb-red);
}

.studio-copy__title {
  font-size: clamp(2rem, 3.6vw, 3.5rem);
  font-weight: var(--weight-bold);
  line-height: 1.12;
  letter-spacing: var(--tracking-tighter);
  color: var(--fb-white);
}

.studio-visual {
  position: relative;
  justify-self: center;
  width: clamp(320px, 34vw, 620px);
}

.studio-visual__meta {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1rem;
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fb-gray);
}

.studio-visual__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--fb-red);
  flex-shrink: 0;
}

.studio-visual__counter {
  margin-left: auto;
  color: var(--fb-white);
}

.studio-visual__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--fb-black);
}

.studio-visual-image {
  position: absolute;
  inset: 0;
  overflow: hidden;
  clip-path: inset(100% 0% 0% 0%);
  will-change: clip-path;
}

.studio-visual-image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.08);
  will-change: transform;
}

/* Per-discipline object-position hook -- adjust framing individually here
   without touching markup, structure, or the reveal/parallax logic. */
.studio-visual-image[data-discipline="strategy"] img { object-position: center center; }
.studio-visual-image[data-discipline="design"] img { object-position: center center; }
.studio-visual-image[data-discipline="motion"] img { object-position: center center; }
.studio-visual-image[data-discipline="technology"] img { object-position: center center; }
.studio-visual-image[data-discipline="3d"] img { object-position: center center; }
.studio-visual-image[data-discipline="cgi"] img { object-position: center center; }

/* EXPERIMENT: glitch transition overlay (see ENABLE_STUDIO_GLITCH in
   main.js). Sits above the plain-wipe .studio-visual-image stack, only
   visible during the brief central window of a state transition; the
   underlying wipe keeps running underneath either way. */
.studio-glitch {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
}

.studio-glitch__slice {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  opacity: 0;
  will-change: transform, clip-path, opacity;
}

.studio-glitch__signal {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--fb-red);
  box-shadow: 0 0 8px rgba(242, 42, 18, 0.35);
  opacity: 0;
}

@media (max-width: 768px) {
  .studio-scroll {
    height: 600svh;
  }

  .studio-sticky {
    /* .nav's real mobile height is ~70px (24px padding + a ~46px logo,
       .nav__logo-img's own <=768px override). 14svh only clears that on
       very tall viewports (>1000px), so the floor is what actually
       guards short/typical phones -- ~86px (70px + margin). */
    --studio-header-safe: clamp(86px, 16svh, 106px);
    height: 100svh;
    min-height: 100svh;
    grid-template-columns: 1fr;
    /* auto: row1 sizes to .studio-visual's own content (meta + the
       frame's explicit clamp height below); 1fr: copy takes whatever is
       left. Combined with align-content:start this can never exceed the
       sticky's own height, so nothing gets clipped by overflow:hidden. */
    grid-template-rows: auto 1fr;
    align-content: start;
    gap: clamp(0.75rem, 2.5svh, 1.5rem);
    padding: var(--studio-header-safe) 1.25rem 1.25rem;
  }

  .studio-copy {
    order: 2;
    align-self: start;
    height: 11rem;
  }

  .studio-visual {
    order: 1;
    align-self: start;
    display: flex;
    flex-direction: column;
    width: min(92vw, 520px);
    margin: 0 auto;
  }

  .studio-visual__meta {
    flex: 0 0 auto;
  }

  .studio-visual__frame {
    flex: 0 0 auto;
    height: clamp(280px, 42svh, 430px);
    aspect-ratio: auto;
  }
}

@media (min-width: 769px) and (max-width: 1024px) {
  /* NOT vw-based: .studio-visual's real available space is the grid's
     inner content box (viewport minus .studio's own padding, minus
     .studio-sticky's own padding, minus the column gap) -- "62vw" of the
     full viewport ends up far larger than 62% of that actual space and
     squeezes .studio-copy down to ~70px. fr keeps both columns
     proportional to the space that's really there; the cap just stops
     the image from getting too wide on the larger end of this range. */
  .studio-sticky {
    grid-template-columns: 0.85fr 1.15fr;
  }

  .studio-visual {
    width: 100%;
    max-width: 720px;
  }

  .studio-visual__frame {
    aspect-ratio: auto;
    height: min(46svh, 500px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .studio-copy__state,
  .studio__label {
    opacity: 1;
    transform: none;
  }

  .studio-visual-image {
    clip-path: inset(0% 0% 0% 0%);
  }

  .studio-visual-image img {
    transform: none;
  }
}

/* ------------------------------------------------------------------ */
/* Clients                                                              */
/* ------------------------------------------------------------------ */

.clients {
  position: relative;
  z-index: 2;
  overflow: clip;
  padding: 110px 3rem 90px;
  background: transparent;
}

/* Very subtle light contamination toward the right edge -- not a visible
   decorative gradient, just a hint of warmth. */
.clients__glow {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(45%, 640px);
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at top right, rgba(242, 42, 18, 0.07), transparent 65%);
}

.clients__inner {
  position: relative;
  z-index: 1;
  max-width: 1400px;
  margin: 0 auto;
}

.clients__top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
}

.clients__heading {
  display: flex;
  flex-direction: column;
  margin-top: 1.25rem;
  max-width: 700px;
}

.clients__line {
  display: block;
  font-size: clamp(1.375rem, 2.2vw, 2.125rem);
  font-weight: var(--weight-bold);
  line-height: 1.24;
  letter-spacing: var(--tracking-tighter);
  color: var(--fb-white);
  opacity: 0;
  transform: translateY(20px);
}

.clients__dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 0.5rem;
  border-radius: 50%;
  background: var(--fb-red);
  vertical-align: middle;
}

.clients__selected {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-shrink: 0;
  padding-bottom: 0.35rem;
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fb-gray);
  white-space: nowrap;
}

.clients__selected-line {
  width: 2.5rem;
  height: 1px;
  background: var(--fb-red);
}

.clients-logo-bands {
  position: relative;
  margin-top: 60px;
  opacity: 0;
  transform: translateY(20px);
}

.clients-logo-bands__divider {
  display: block;
  height: 1px;
  background: rgba(255, 255, 255, 0.08);
}

.clients-logo-row {
  height: 100px;
  overflow: hidden;
  display: flex;
  align-items: center;
}

.clients-logo-track {
  display: flex;
  align-items: center;
  gap: 90px;
  width: max-content;
  will-change: transform;
  animation-duration: 42s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

.clients-logo-row--left .clients-logo-track {
  animation-name: clients-marquee-left;
}

.clients-logo-row--right .clients-logo-track {
  animation-name: clients-marquee-right;
}

.clients-logo-row:hover .clients-logo-track {
  animation-play-state: paused;
}

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

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

.clients-logo-item {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.clients-logo-item img {
  display: block;
  max-height: 52px;
  width: auto;
  object-fit: contain;
  filter: grayscale(1) brightness(1.4);
  opacity: 0.72;
  transition: filter 0.4s ease, opacity 0.4s ease, transform 0.4s ease;
}

.clients-logo-item:hover img,
.clients-logo-item:focus-within img {
  filter: grayscale(0) brightness(1);
  opacity: 1;
  transform: scale(1.03);
}

@media (max-width: 768px) {
  .clients {
    padding: 90px 1.5rem 70px;
  }

  .clients__top {
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
  }

  .clients__selected {
    padding-bottom: 0;
  }

  .clients-logo-bands {
    margin-top: 40px;
  }

  .clients-logo-row {
    height: 74px;
  }

  .clients-logo-track {
    gap: 50px;
  }

  .clients-logo-item img {
    max-height: 38px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .clients__line,
  .clients-logo-bands {
    opacity: 1;
    transform: none;
  }

  .clients-logo-track {
    animation: none;
  }
}

/* ------------------------------------------------------------------ */
/* Capabilities                                                         */
/* ------------------------------------------------------------------ */

.capabilities {
  position: relative;
  z-index: 2;
  padding: 8rem 3rem 10rem;
  background: transparent;
}

.capabilities__header {
  max-width: 1400px;
  margin: 0 auto;
}

.capabilities__header-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
}

.capabilities__header-row .eyebrow {
  margin-bottom: 0;
}

.capabilities__meta {
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fb-gray);
  opacity: 0.6;
  white-space: nowrap;
}

.capabilities__heading {
  font-size: clamp(1.75rem, 3.4vw, 2.75rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: var(--tracking-tight);
  max-width: 700px;
  margin-top: 2.5rem;
  margin-bottom: 5rem;
}

.capabilities__track {
  position: relative;
  height: 400vh;
}

.capabilities__pin {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

/* Cinematic visual -- one shared stage holding all four systems' videos,
   stacked on top of each other. JS (initCapabilities) crossfades opacity
   so only the active system's video is visible, driven by the same
   progress/index that opens each door -- no separate ScrollTrigger.
   ONE shared darkening treatment (opacity + filter + overlay below)
   applies identically to all four -- no per-video overrides. */
.capabilities__visual {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}

.capabilities__visual-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  opacity: 0;
  filter: brightness(0.66) contrast(1.05);
}

.capabilities__visual-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(11, 8, 8, 0.32);
}

.capabilities__states {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
}

/* Minimalist dot indicator -- integrated into the same master state
   index (see initCapabilities in main.js); no ScrollTrigger of its own. */
.capabilities__dots {
  position: absolute;
  left: 50%;
  bottom: clamp(1.5rem, 4vh, 2.5rem);
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  gap: 0.6rem;
}

.capabilities__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--fb-gray);
  opacity: 0.5;
  transition: background-color 0.4s ease, opacity 0.4s ease, transform 0.4s ease;
}

.capabilities__dot.is-active {
  background: var(--fb-red);
  opacity: 1;
  transform: scale(1.3);
}

.capabilities__state {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
}

.capabilities__door {
  position: relative;
  z-index: 1;
  width: min(90vw, 620px);
  text-align: center;
  clip-path: inset(50% 50% 50% 50%);
}

.capabilities__door-index {
  font-size: 0.8125rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.14em;
  color: var(--fb-red);
  margin-bottom: 1rem;
}

.capabilities__door-title {
  font-size: clamp(1.75rem, 3.2vw, 3rem);
  font-weight: var(--weight-bold);
  letter-spacing: -0.03em;
  margin-bottom: 1.1rem;
}

.capabilities__door-desc {
  font-size: 0.9375rem;
  line-height: 1.75;
  color: var(--fb-white);
  opacity: 0.7;
  margin-bottom: 1.5rem;
}

.capabilities__door-disciplines {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1.25rem;
}

.capabilities__door-disciplines li {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fb-gray);
}

.capabilities__door-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.5rem;
  padding: 0;
  background: none;
  border: none;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.04em;
  color: var(--fb-red);
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 0.3s ease, gap 0.3s ease;
}

.capabilities__door-cta:hover,
.capabilities__door-cta:focus-visible {
  opacity: 1;
  gap: 0.75rem;
}

/* ------------------------------------------------------------------ */
/* Process                                                              */
/* ------------------------------------------------------------------ */

.process {
  position: relative;
  z-index: 2;
  padding: 10rem 3rem;
  background: transparent;
}

.process__header {
  max-width: 1000px;
  margin: 0 auto;
}

.process__heading {
  font-size: clamp(1.75rem, 3.4vw, 2.75rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: var(--tracking-tight);
  max-width: 650px;
  margin-bottom: 5rem;
}

/* Mobile-only accordion trigger (Process + Lab share this styling) --
   hidden unconditionally here; the <=768px block below is what actually
   shows it, so desktop/tablet never render it at all. */
.process__accordion-toggle,
.lab__accordion-toggle {
  display: none;
}

/* Text left / sticky visual right -- the existing single master
   ScrollTrigger in initProcess() (main.js) already drives .process-step's
   .is-active state off one progress value; it now also toggles the
   matching .process-visual-card's .is-active off that same value (plus a
   small stack-level translateY), so this is purely a layout addition, not
   a second scroll system. */
.process__body {
  max-width: 1280px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(320px, 0.9fr) minmax(560px, 1.4fr);
  column-gap: clamp(48px, 6vw, 110px);
  align-items: start;
}

.process__list {
  position: relative;
  padding-left: 3rem;
}

/* Six wide cinematic strips in normal flow, overlapped purely with
   negative margin-top -- robust to the column's own responsive width,
   unlike absolute-positioned offsets. translateX/rotate are per-card only
   (they don't affect layout), so the stack still reads as one aligned
   column with only a whisper of depth. All six stay mounted and visible;
   only opacity/filter/scale/border distinguish the active one. */
.process-visual-stack {
  position: sticky;
  top: 140px;
  transition: transform 0.5s var(--ease-out);
}

.process-visual-card {
  position: relative;
  width: 100%;
  height: clamp(130px, 12vw, 175px);
  margin-top: -24px;
  overflow: hidden;
  border-radius: 3px;
  border: 1px solid rgba(244, 242, 237, 0.09);
  background: rgba(11, 8, 8, 0.35);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.32);
  opacity: 0.4;
  filter: brightness(0.62) saturate(0.78);
  transform: translateX(var(--card-x, 0)) rotate(var(--card-rot, 0deg)) scale(0.985);
  transition: opacity 420ms ease, filter 420ms ease,
    transform 520ms var(--ease-out), border-color 320ms ease,
    box-shadow 320ms ease, z-index 0s 0.25s;
  z-index: 1;
}

.process-visual-card:first-child {
  margin-top: 0;
}

.process-visual-card.is-active {
  opacity: 1;
  filter: brightness(1) saturate(1);
  transform: translateX(var(--card-x, 0)) rotate(var(--card-rot, 0deg)) scale(1);
  border-color: rgba(244, 242, 237, 0.72);
  box-shadow: 0 18px 42px rgba(0, 0, 0, 0.48), 0 0 18px rgba(244, 242, 237, 0.05),
    0 0 20px rgba(242, 42, 18, 0.06);
  z-index: 10;
  transition: opacity 420ms ease, filter 420ms ease,
    transform 520ms var(--ease-out), border-color 320ms ease,
    box-shadow 320ms ease, z-index 0s;
}

/* Tiny corner marker -- the ONLY other red on the card besides the index;
   the border itself stays white/gray per spec. */
.process-visual-card.is-active::after {
  content: '';
  position: absolute;
  top: 10px;
  right: 10px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--fb-red);
  box-shadow: 0 0 8px rgba(242, 42, 18, 0.7);
  z-index: 2;
}

.process-visual-card[data-step="0"] { --card-x: 18px; --card-rot: -0.4deg; }
.process-visual-card[data-step="1"] { --card-x: -4px; --card-rot: 0.25deg; }
.process-visual-card[data-step="2"] { --card-x: 28px; --card-rot: -0.2deg; }
.process-visual-card[data-step="3"] { --card-x: 4px; --card-rot: 0.35deg; }
.process-visual-card[data-step="4"] { --card-x: 20px; --card-rot: -0.25deg; }
.process-visual-card[data-step="5"] { --card-x: -2px; --card-rot: 0.2deg; }

.process-visual-card img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
}

.process-visual-card__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    rgba(11, 8, 8, 0.5) 0%,
    rgba(11, 8, 8, 0.16) 38%,
    rgba(11, 8, 8, 0.1) 65%,
    rgba(11, 8, 8, 0.38) 100%
  );
  pointer-events: none;
}

.process-visual-card__copy {
  position: absolute;
  left: 24px;
  bottom: 20px;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.process-visual-card__title {
  font-size: 0.72rem;
  font-weight: var(--weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fb-white);
}

.process-visual-card__index {
  font-weight: var(--weight-light);
  color: var(--fb-red);
  margin-right: 0.4em;
}

.process-visual-card__micro {
  font-size: 0.62rem;
  font-weight: var(--weight-light);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(244, 242, 237, 0.6);
}

/* Tablet: still all six, still aligned columns, just gentler -- half the
   horizontal offset/rotation, tighter overlap, shorter cards, and a
   narrower minimum for the visual column so 768-1100px never has to
   fight the desktop 560px floor for room. */
@media (max-width: 1100px) and (min-width: 768px) {
  .process__body {
    grid-template-columns: minmax(260px, 0.9fr) minmax(300px, 1.2fr);
    column-gap: clamp(28px, 4vw, 56px);
  }

  .process-visual-card {
    height: clamp(100px, 14vw, 140px);
    margin-top: -14px;
  }

  .process-visual-card[data-step="0"] { --card-x: 9px; --card-rot: -0.2deg; }
  .process-visual-card[data-step="1"] { --card-x: -2px; --card-rot: 0.13deg; }
  .process-visual-card[data-step="2"] { --card-x: 14px; --card-rot: -0.1deg; }
  .process-visual-card[data-step="3"] { --card-x: 2px; --card-rot: 0.18deg; }
  .process-visual-card[data-step="4"] { --card-x: 10px; --card-rot: -0.13deg; }
  .process-visual-card[data-step="5"] { --card-x: -1px; --card-rot: 0.1deg; }
}

/* Mobile: the six-card wall doesn't fit -- one dominant active card plus a
   single ghost card peeking just behind it, instead of either the full
   desktop stack or a flat single image. Single-column stacking (moved down
   from the old 900px cutoff) starts here too, so the two-column tablet
   layout above correctly persists through the full 768-1100px range. */
@media (max-width: 767px) {
  .process__body {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }

  .process-visual-stack {
    position: relative;
    top: auto;
    height: clamp(180px, 52vw, 230px);
    margin-top: 1.5rem;
  }

  .process-visual-card {
    position: absolute;
    inset: 0;
    margin-top: 0;
    height: auto;
    opacity: 0;
    transform: none !important;
    pointer-events: none;
  }

  .process-visual-card.is-active {
    opacity: 1;
    z-index: 10;
  }

  .process-visual-card.is-ghost {
    opacity: 0.16;
    transform: translateY(10px) scale(0.96) !important;
    z-index: 5;
  }
}

.process__line {
  position: absolute;
  left: 0;
  top: 0.5rem;
  bottom: 0.5rem;
  width: 1px;
  background: rgba(255, 255, 255, 0.1);
}

.process__line-fill {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 0%;
  background: var(--fb-red);
  box-shadow: 0 0 12px rgba(242, 42, 18, 0.6);
}

.process-step {
  position: relative;
  padding: 2rem 0 2rem 2rem;
  opacity: 0.4;
  transition: opacity 0.5s ease;
}

.process-step::before {
  content: '';
  position: absolute;
  left: -3.5rem;
  top: 2.4rem;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--fb-gray);
  transition: background 0.4s ease, box-shadow 0.4s ease;
}

.process-step.is-active {
  opacity: 1;
}

.process-step.is-active::before {
  background: var(--fb-red);
  box-shadow: 0 0 10px rgba(242, 42, 18, 0.7);
}

.process-step__index {
  display: block;
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.1em;
  color: var(--fb-gray);
  margin-bottom: 0.5rem;
}

.process-step__title {
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
  text-transform: uppercase;
  margin-bottom: 0.5rem;
}

.process-step__desc {
  font-size: 0.9375rem;
  color: var(--fb-gray);
  line-height: 1.6;
  max-width: 480px;
}

/* ------------------------------------------------------------------ */
/* Lab / Insights                                                       */
/* ------------------------------------------------------------------ */

.lab {
  position: relative;
  z-index: 2;
  padding: 10rem 3rem;
  background: transparent;
}

.lab__header,
.lab__list {
  max-width: 1200px;
  margin: 0 auto;
}

.lab__heading {
  font-size: clamp(1.75rem, 3.4vw, 2.75rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: var(--tracking-tight);
  margin-bottom: 5rem;
}

.lab-entry {
  display: grid;
  grid-template-columns: 60px 160px 1fr 120px 40px;
  align-items: center;
  gap: 2rem;
  padding: 2rem 0;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  color: var(--fb-white);
}

.lab__list a.lab-entry:last-child {
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.lab-entry__index {
  font-size: 0.8125rem;
  font-weight: var(--weight-light);
  color: var(--fb-gray);
}

.lab-entry__category {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fb-gray);
}

.lab-entry__title {
  font-size: clamp(1.125rem, 2vw, 1.5rem);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  transition: color 0.3s ease;
}

.lab-entry__date {
  font-size: 0.75rem;
  color: var(--fb-gray);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.lab-entry__arrow {
  font-size: 1.125rem;
  color: var(--fb-gray);
  transition: color 0.3s ease, transform 0.3s ease;
  justify-self: end;
}

.lab-entry:hover .lab-entry__title,
.lab-entry:hover .lab-entry__arrow {
  color: var(--fb-red);
}

.lab-entry:hover .lab-entry__arrow {
  transform: translateX(4px);
}

/* ------------------------------------------------------------------ */
/* Business Scan hero (homepage teaser)                                */
/* ------------------------------------------------------------------ */

/* Layered composition: video layer (video + overlay + gradient) sits at
   the bottom of the section's own stacking context; .business-scan-content
   sits on top via z-index. Section itself carries an opaque dark
   background-color as the fallback -- if the video never loads (blocked,
   slow connection, decode failure) the section still reads as a clean,
   on-brand dark panel instead of a blank/broken box, so there is no
   layout shift and no empty flash either way. */
.business-scan-hero {
  position: relative;
  z-index: 2;
  overflow: hidden;
  min-height: 92vh;
  display: flex;
  align-items: center;
  padding: 7rem 3rem;
  background: var(--fb-black);
}

.business-scan-video-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Filter darkens/tames the footage itself (uniformly, across the whole
   frame) -- the overlay + gradient divs below add the *directional*
   darkening on top of that. Kept inside the suggested range and toward
   its gentler end so shadow detail and the red/orange highlights survive
   rather than crushing to flat black. */
.business-scan-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  filter: brightness(0.62) contrast(1.08) saturate(0.92);
}

/* Flat, subtle base darkening across the whole frame -- deliberately
   light on its own; the gradient layer below does the heavy lifting
   exactly where the content needs it (left text, right panels), so the
   open middle of the frame (where the video's own character/subject
   sits) stays comparatively well-lit and detailed. */
.business-scan-overlay {
  position: absolute;
  inset: 0;
  background: rgba(11, 8, 8, 0.38);
}

/* Three stacked, purely-black gradients (stacking order doesn't change
   the combined darkness for same-color layers, so this reads top to
   bottom as: readability gradient behind the left text -> a soft pool
   behind the right-side HUD panels -> a light vignette on the outer
   edges only). Center-right, where the video's own subject sits, is
   deliberately left the lightest of the three so detail and the red/
   orange highlights stay visible. */
.business-scan-gradient {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(11, 8, 8, 0.86) 0%, rgba(11, 8, 8, 0.55) 36%, rgba(11, 8, 8, 0.42) 52%, rgba(11, 8, 8, 0.22) 100%),
    radial-gradient(ellipse 460px 420px at 82% 45%, rgba(8, 6, 6, 0.4) 0%, rgba(8, 6, 6, 0) 72%),
    radial-gradient(ellipse 92% 92% at 50% 50%, rgba(0, 0, 0, 0) 58%, rgba(8, 6, 6, 0.32) 100%);
}

.business-scan-content {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 3rem;
  row-gap: 4.5rem;
}

.business-scan-left {
  grid-column: 1;
  grid-row: 1;
  max-width: 600px;
}

/* Mobile-only per spec -- desktop/tablet composition (eyebrow text +
   headline) stays exactly as it is. Hidden here unconditionally so the
   <=768px override below is what actually turns it on. */
.business-scan-mobile-logo {
  display: none;
}

.business-scan-heading {
  font-size: clamp(2.1rem, 4vw, 3.4rem);
  font-weight: var(--weight-bold);
  line-height: 1.1;
  letter-spacing: var(--tracking-tight);
  color: var(--fb-white);
  margin-bottom: 1.5rem;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.35);
}

.bscan-emphasis {
  color: var(--fb-red);
}

.business-scan-sub {
  font-size: 1rem;
  line-height: 1.55;
  color: rgba(244, 242, 237, 0.78);
  margin-bottom: 2rem;
  max-width: 42ch;
}

/* Primary CTA -- its own rule set rather than an extension of the shared
   .btn (which stays the outlined/transparent treatment everywhere else
   on the site, e.g. Hero's CTA). This one is a strong filled red per
   spec, so it is deliberately NOT sharing .btn's styling or hover rule. */
.business-scan-cta {
  appearance: none;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 1.05rem 2.4rem;
  font-size: 0.9375rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.02em;
  color: var(--fb-white);
  background: linear-gradient(135deg, #ff3d24 0%, var(--fb-red) 100%);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 100px;
  box-shadow: 0 8px 28px rgba(242, 42, 18, 0.45), 0 0 50px rgba(242, 42, 18, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.22);
  transition: transform 0.35s var(--ease-out), box-shadow 0.35s var(--ease-out), filter 0.35s var(--ease-out);
  opacity: 0;
  margin-bottom: 1.5rem;
}

.business-scan-cta:hover {
  transform: translateY(-2px);
  filter: brightness(1.06);
  box-shadow: 0 10px 34px rgba(242, 42, 18, 0.55), 0 0 60px rgba(242, 42, 18, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.26);
}

.business-scan-cta .btn__arrow {
  transition: transform 0.35s var(--ease-out);
}

.business-scan-cta:hover .btn__arrow {
  transform: translateX(4px);
}

.business-scan-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  list-style: none;
  padding: 0;
  margin: 0;
  opacity: 0;
}

.business-scan-tags li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  color: rgba(244, 242, 237, 0.75);
}

.business-scan-tags__dot {
  width: 5px;
  height: 5px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--fb-red);
}

/* Right side -- ONE unified glass panel (score + description + a divider
   + the opportunities list), rather than two separate cards, per spec.
   Illustrative preview of the tool's own output, not live data
   (aria-hidden in the markup). */
.business-scan-hud {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  width: 320px;
}

.bscan-panel {
  background: rgba(8, 6, 6, 0.72);
  border: 1px solid rgba(242, 42, 18, 0.22);
  border-radius: 18px;
  padding: 1.75rem 1.75rem 1.5rem;
  backdrop-filter: blur(8px) saturate(130%);
  -webkit-backdrop-filter: blur(8px) saturate(130%);
  box-shadow: 0 0 44px rgba(242, 42, 18, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  opacity: 0;
  transform: translateY(16px);
}

.bscan-panel__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.bscan-panel__label {
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(244, 242, 237, 0.92);
  line-height: 1.35;
}

.bscan-panel__tag {
  flex-shrink: 0;
  font-size: 0.5625rem;
  font-weight: var(--weight-regular);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fb-red);
  border: 1px solid rgba(242, 42, 18, 0.4);
  border-radius: 100px;
  padding: 0.3rem 0.65rem;
  white-space: nowrap;
}

.bscan-score-row {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin-bottom: 1.5rem;
}

.bscan-hud-score {
  position: relative;
  width: 76px;
  height: 76px;
  flex-shrink: 0;
}

.bscan-hud-score__ring {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.bscan-hud-score__track {
  fill: none;
  stroke: rgba(244, 242, 237, 0.1);
  stroke-width: 7;
}

.bscan-hud-score__fill {
  fill: none;
  stroke: var(--fb-red);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-dasharray: 326.7;
  stroke-dashoffset: 326.7;
  filter: drop-shadow(0 0 5px rgba(242, 42, 18, 0.75));
}

.bscan-hud-score__value {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1;
  font-size: 1.375rem;
  font-weight: var(--weight-bold);
  color: var(--fb-white);
}

.bscan-hud-score__value small {
  font-size: 0.5625rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.04em;
  color: var(--fb-gray);
  margin-top: 0.15rem;
}

.bscan-panel__desc {
  font-size: 0.8125rem;
  line-height: 1.5;
  color: rgba(244, 242, 237, 0.85);
}

.bscan-panel__divider {
  height: 1px;
  background: rgba(244, 242, 237, 0.12);
  margin-bottom: 1.25rem;
}

.bscan-panel__subheading {
  display: block;
  font-size: 0.625rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fb-gray);
  margin-bottom: 0.5rem;
}

.bscan-opp-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.bscan-opp-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.7rem 0;
  border-top: 1px solid rgba(244, 242, 237, 0.08);
}

.bscan-opp-row:first-child {
  border-top: none;
}

.bscan-opp-row__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border: 1px solid rgba(242, 42, 18, 0.3);
  border-radius: 50%;
  background: rgba(242, 42, 18, 0.12);
  color: var(--fb-red);
}

.bscan-opp-row__icon svg {
  width: 13px;
  height: 13px;
}

.bscan-opp-row__label {
  flex: 1;
  font-size: 0.8125rem;
  color: rgba(244, 242, 237, 0.88);
}

.bscan-opp-row__arrow {
  color: var(--fb-gray);
  font-size: 0.9375rem;
}

/* Bottom strip -- one connected dark panel (not a bare row) holding the
   3 feature blocks, each with its own icon + title + description. */
.business-scan-features {
  grid-column: 1 / -1;
  grid-row: 2;
  display: flex;
  flex-wrap: wrap;
  margin-top: 1rem;
  background: rgba(8, 6, 6, 0.55);
  border: 1px solid rgba(244, 242, 237, 0.12);
  border-radius: 16px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  overflow: hidden;
}

.bscan-feature {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex: 1 1 260px;
  padding: 1.5rem 1.75rem;
  border-left: 1px solid rgba(244, 242, 237, 0.1);
}

.bscan-feature:first-child {
  border-left: none;
}

.bscan-feature__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border: 1px solid rgba(242, 42, 18, 0.3);
  border-radius: 50%;
  background: rgba(242, 42, 18, 0.12);
  color: var(--fb-red);
}

.bscan-feature__icon svg {
  width: 17px;
  height: 17px;
}

.bscan-feature__copy {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.bscan-feature__title {
  font-size: 0.875rem;
  font-weight: var(--weight-bold);
  color: var(--fb-white);
}

.bscan-feature__desc {
  font-size: 0.75rem;
  color: var(--fb-gray);
}

/* ------------------------------------------------------------------ */
/* Contact                                                              */
/* ------------------------------------------------------------------ */

.contact {
  position: relative;
  z-index: 2;
  min-height: 100svh;
  display: flex;
  /* flex-start, not center: the two-column content (headline + copy vs a
     5-field form panel) is often taller than 100svh on real desktop/laptop
     heights, and a centered flex child overflows its box symmetrically --
     pushing the top past the section's own edge and under the fixed nav.
     Top-aligned + the existing 8rem top padding clears the nav the same
     way every other section already does; min-height still gives short
     content the full cinematic-closing-scene height. */
  align-items: flex-start;
  /* Bottom padding is intentionally NOT symmetric with the top: 8rem there
     clears the fixed nav, but the same 8rem below the footer was pure dead
     space (measured live: footer bottom sat 128px above the section's own
     bottom edge on desktop) -- that's the extra scroll distance that let
     the page run past the intended final composition. 3rem gives the
     footer real but proportionate breathing room instead. */
  padding: 8rem 3rem 3rem;
  background: var(--fb-black);
  overflow: hidden;
}

/* Full-bleed cinematic loop, plain autoplay -- NOT scroll-scrubbed. A single
   horizontal gradient overlay both darkens the left/right thirds (where the
   copy and form panel sit) and keeps the middle third -- the environment's
   central opening -- the clearest part of the frame, in one declaration
   instead of separate left/right treatments. */
.contact__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}

.contact__bg-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  opacity: 0.74;
  filter: brightness(0.72) contrast(1.05);
}

.contact__bg-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    rgba(11, 8, 8, 0.64) 0%,
    rgba(11, 8, 8, 0.24) 32%,
    rgba(11, 8, 8, 0.2) 68%,
    rgba(11, 8, 8, 0.64) 100%
  );
}

.contact__content {
  position: relative;
  z-index: 1;
  max-width: 1360px;
  margin: 0 auto;
  width: 100%;
}

.contact__grid {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  align-items: start;
  gap: clamp(2.5rem, 6vw, 6rem);
  margin-bottom: 4rem;
}

.contact__eyebrow-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--fb-red);
}

.contact__heading {
  font-size: clamp(3rem, 7vw, 6rem);
  font-weight: var(--weight-bold);
  line-height: 1.05;
  letter-spacing: var(--tracking-tighter);
  margin-bottom: 2.5rem;
}

.contact__lines {
  font-size: clamp(1.125rem, 2.2vw, 1.5rem);
  font-weight: var(--weight-light);
  line-height: 1.5;
  color: var(--fb-gray);
  margin-bottom: 2.5rem;
}

.contact__intro {
  font-size: 1rem;
  font-weight: var(--weight-regular);
  line-height: 1.7;
  color: var(--fb-gray);
  max-width: 440px;
}

/* Dark glass panel -- part of the cinematic environment, not a white UI
   card. The <form> element itself is the panel (header + fields share one
   box) so the existing entrance ScrollTrigger on .contact__form (see
   initContact() in main.js) keeps animating the whole thing as one unit;
   no new trigger needed. */
.contact__form {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem 2rem;
  padding: clamp(1.75rem, 3vw, 2.5rem);
  background: rgba(11, 8, 8, 0.62);
  border: 1px solid rgba(244, 242, 237, 0.12);
  border-radius: 6px;
  backdrop-filter: blur(16px) saturate(110%);
  -webkit-backdrop-filter: blur(16px) saturate(110%);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
}

.contact__form-header {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.5rem;
  padding-bottom: 1.1rem;
  border-bottom: 1px solid rgba(244, 242, 237, 0.1);
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--fb-white);
}

.contact__form-header-dot {
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  background: var(--fb-red);
}

.contact__field {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.contact__field--full {
  grid-column: 1 / -1;
}

.contact__field-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.contact__field label {
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fb-gray);
}

.contact__counter {
  font-size: 0.625rem;
  font-weight: var(--weight-light);
  color: var(--fb-gray);
  letter-spacing: 0.02em;
}

.contact__field input,
.contact__field textarea {
  background: rgba(0, 0, 0, 0.22);
  border: 1px solid rgba(244, 242, 237, 0.12);
  border-radius: 3px;
  padding: 0.6rem 0.75rem;
  font-family: var(--font);
  font-size: 0.9375rem;
  font-weight: var(--weight-regular);
  color: var(--fb-white);
  transition: border-color 0.3s ease, background-color 0.3s ease;
  resize: none;
}

.contact__field input::placeholder,
.contact__field textarea::placeholder {
  color: var(--fb-gray);
}

.contact__field input:focus,
.contact__field textarea:focus {
  outline: none;
  border-color: var(--fb-red);
  background: rgba(0, 0, 0, 0.32);
}

.contact__submit {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.5rem;
  padding: 1rem 2.2rem;
  background: linear-gradient(135deg, var(--fb-red), #8f160d);
  border: 1px solid transparent;
  border-radius: 3px;
  color: var(--fb-white);
  font-family: var(--font);
  font-size: 0.9375rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: filter 0.3s ease, gap 0.3s ease;
}

.contact__submit:hover {
  filter: brightness(1.12);
  gap: 0.9rem;
}

.contact__submit .btn__arrow {
  transition: transform 0.3s ease;
}

.contact__submit:hover .btn__arrow {
  transform: translateX(3px);
}

.contact__form-note {
  grid-column: 1 / -1;
  font-size: 0.8125rem;
  color: var(--fb-gray);
  min-height: 1.2em;
}

.contact__trust {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  color: var(--fb-gray);
}

.contact__trust-icon {
  width: 11px;
  height: 11px;
  flex-shrink: 0;
  color: var(--fb-gray);
}

.contact__footer {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.contact__copy {
  font-size: 0.8125rem;
  color: var(--fb-gray);
}

/* 1100px, not 900px: measured live, the two-column grid squeezes
   .contact__left just enough between ~901-1075px that "hacer realidad?"
   (longer than the old "crear?") wraps onto a 3rd line instead of staying
   on line 2 with "hacer". 1100px matches the project's existing
   intermediate/adaptive breakpoint (see .nav__backdrop above) and is
   comfortably clear of that range. */
@media (max-width: 1100px) {
  .contact__grid {
    grid-template-columns: 1fr;
  }

  .contact__intro {
    max-width: 100%;
  }
}

@media (max-width: 768px) {
  .contact {
    min-height: 0;
    padding: 6rem 1.5rem 4rem;
  }

  .contact__bg-overlay {
    background: rgba(11, 8, 8, 0.56);
  }

  .contact__form {
    grid-template-columns: 1fr;
  }
}

.reveal-text {
  opacity: 0;
}

.reveal-up {
  opacity: 0;
  transform: translateY(40px);
}

/* ------------------------------------------------------------------ */
/* Business Scan interactive modal -- full diagnostic flow (intro,     */
/* questions, results, lead capture) opened by #businessScanOpenModal. */
/* Same structural pattern as .digital-systems-backdrop /               */
/* .portfolio-gallery-backdrop above: fixed root-level overlay, html-   */
/* level scroll lock, Escape + backdrop-click-only to close. Driven    */
/* entirely by business-scan-modal.js, which reuses window.FlyboyI18n  */
/* from main.js instead of a separate language state.                  */
/* ------------------------------------------------------------------ */

html.bscan-modal-lock,
html.bscan-modal-lock body {
  overflow: hidden !important;
}

.bscan-modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4vh 2vw;
  background: rgba(0, 0, 0, 0.48);
  backdrop-filter: blur(5px) saturate(0.9);
  -webkit-backdrop-filter: blur(5px) saturate(0.9);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.bscan-modal-backdrop.is-open {
  pointer-events: auto;
}

.bscan-modal__window {
  position: relative;
  width: min(92vw, 1100px);
  height: auto;
  max-height: min(90vh, 780px);
  display: flex;
  flex-direction: column;
  background: linear-gradient(135deg, rgba(30, 30, 30, 0.6) 0%, rgba(10, 10, 10, 0.48) 100%);
  backdrop-filter: blur(26px) saturate(115%);
  -webkit-backdrop-filter: blur(26px) saturate(115%);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 32px;
  overflow: hidden;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    inset 1px 0 0 rgba(255, 255, 255, 0.09),
    inset 0 -1px 0 rgba(255, 60, 40, 0.16),
    inset -1px 0 0 rgba(255, 60, 40, 0.1),
    0 25px 80px rgba(0, 0, 0, 0.55),
    0 0 1px rgba(255, 255, 255, 0.25),
    0 0 34px rgba(255, 40, 25, 0.1);
  opacity: 0;
  transform: scale(0.97) translateY(16px);
}

/* Realistic (not uniform-neon) edge lighting + milky glass diffusion, all
   layered into one pseudo-element: a soft white highlight hugging the
   top-left corner, red reflections concentrated at the bottom-right
   corner and upper-right edge (asymmetric, like a real light source
   off to one side -- NOT a glowing outline all the way round), and a
   very faint cloudy wash behind the headline for that frosted-glass
   diffusion feel. Sits above the background gradient, below the grain
   and content (z-index order matches ::after's 5 / body's 10). */
.bscan-modal__window::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background:
    radial-gradient(120px 90px at 6% 4%, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0) 70%),
    radial-gradient(240px 200px at 98% 102%, rgba(255, 50, 32, 0.18), rgba(255, 50, 32, 0) 70%),
    radial-gradient(180px 260px at 100% 15%, rgba(255, 50, 32, 0.09), rgba(255, 50, 32, 0) 70%),
    radial-gradient(70% 46% at 50% 28%, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0) 65%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0) 16%);
}

/* Dedicated static grain texture -- the global .flyboy-global-grain sits
   behind all site content (z-index 1), well below this modal's z-index
   600, so it can never show through here. Rather than wiring a second
   live mountGrain() instance across files, a lightweight static noise
   tile (same subtle screen-blend technique, same ballpark opacity) gives
   the window the same textured surface at effectively zero cost. */
.bscan-modal__window::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: screen;
  opacity: 0.05;
}

.bscan-modal__header {
  position: relative;
  z-index: 10;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem 1.75rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.bscan-modal__eyebrow {
  font-size: 0.6875rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fb-white);
}

.bscan-modal__eyebrow::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 0.6rem;
  border-radius: 50%;
  background: var(--fb-red);
  box-shadow: 0 0 8px rgba(242, 42, 18, 0.8);
  vertical-align: middle;
}

.bscan-modal__header-actions {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

.bscan-modal__esc-hint {
  font-size: 0.625rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fb-gray);
  padding-right: 0.9rem;
  border-right: 1px solid rgba(255, 255, 255, 0.14);
}

.bscan-modal__close {
  appearance: none;
  cursor: pointer;
  font-family: inherit;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 50%;
  color: var(--fb-white);
  font-size: 1.25rem;
  line-height: 1;
  transition: border-color 0.3s ease, color 0.3s ease, transform 0.3s ease;
}

.bscan-modal__close:hover {
  border-color: var(--fb-red);
  color: var(--fb-red);
  transform: rotate(90deg);
  box-shadow: 0 0 16px rgba(242, 42, 18, 0.35);
}

.bscan-modal__body {
  position: relative;
  z-index: 10;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(242, 42, 18, 0.55) transparent;
  padding: clamp(1.5rem, 3vw, 2rem);
}

.bscan-modal__body::-webkit-scrollbar {
  width: 6px;
}

.bscan-modal__body::-webkit-scrollbar-track {
  background: transparent;
}

.bscan-modal__body::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, rgba(242, 42, 18, 0.75), rgba(242, 42, 18, 0.35));
  border-radius: 999px;
}

/* Screens -- exactly one visible at a time via the native [hidden]
   attribute. Explicit [hidden]{display:none} because author rules that
   set display on the SAME element (.bscan-screen{display:flex}) share
   the browser's own [hidden] rule's specificity and, coming later in the
   stylesheet, would otherwise silently win and show a "hidden" screen --
   the same class of bug already found once in this codebase (.btn's
   default opacity:0 trap). */
.bscan-screen {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  max-width: 720px;
  margin: 0 auto;
}

.bscan-screen[hidden] {
  display: none;
}

.bscan-screen--wide {
  max-width: 920px;
}

/* Intro */

.bscan-intro {
  text-align: center;
  align-items: center;
  padding-block: clamp(0.25rem, 1.5vh, 1rem);
  gap: 1.375rem;
}

.bscan-intro__logo {
  display: block;
  width: clamp(105px, 8vw, 125px);
  height: auto;
  object-fit: contain;
  margin: 0 auto;
}

.bscan-intro__title {
  font-size: clamp(1.5rem, 3.4vw, 2.15rem);
  font-weight: var(--weight-bold);
  line-height: 1.25;
  letter-spacing: var(--tracking-tight);
}

.bscan-intro__body {
  font-size: 1rem;
  line-height: 1.65;
  color: var(--fb-gray);
  max-width: 520px;
}

.bscan-intro__meta {
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fb-gray);
  opacity: 0.75;
}

/* Bottom feature strip -- scoped to the modal intro (bscan-intro__feature*,
   not bscan-feature*) so it never touches the hero's own .bscan-feature
   strip, which shares similar copy/icon conventions but different sizing
   and must stay untouched. */
.bscan-intro__features {
  align-self: stretch;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 0.125rem;
  padding-top: 1.1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.bscan-intro__feature {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  flex: 1 1 220px;
  padding: 0.125rem 1.25rem;
  border-left: 1px solid rgba(255, 255, 255, 0.08);
  text-align: left;
}

.bscan-intro__feature:first-child {
  border-left: none;
}

.bscan-intro__feature-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: 1px solid rgba(242, 42, 18, 0.35);
  border-radius: 9px;
  background: rgba(242, 42, 18, 0.1);
  color: var(--fb-red);
  box-shadow: 0 0 14px rgba(242, 42, 18, 0.18);
}

.bscan-intro__feature-icon svg {
  width: 15px;
  height: 15px;
}

.bscan-intro__feature-text {
  font-size: 0.8125rem;
  font-weight: var(--weight-regular);
  color: var(--fb-white);
  line-height: 1.35;
}

/* Buttons -- scoped to the modal so the site's shared .btn (opacity:0
   base rule, revealed only by a scroll ScrollTrigger elsewhere) and
   .business-scan-cta (hero-only) both stay untouched. */

.bscan-btn {
  appearance: none;
  cursor: pointer;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 0.9rem 2rem;
  font-size: 0.875rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.02em;
  border-radius: 100px;
  transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out), filter 0.3s var(--ease-out), border-color 0.3s ease, color 0.3s ease;
}

.bscan-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Same author-vs-UA-stylesheet specificity trap as .bscan-screen[hidden]
   above: .bscan-btn{display:inline-flex} shares [hidden]{display:none}'s
   specificity and, coming later in the stylesheet, would otherwise win. */
.bscan-btn[hidden] {
  display: none;
}

.bscan-btn--primary {
  color: var(--fb-white);
  background: linear-gradient(135deg, #ff3d24 0%, var(--fb-red) 100%);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 8px 28px rgba(242, 42, 18, 0.4), 0 0 50px rgba(242, 42, 18, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.bscan-btn--primary:hover:not(:disabled) {
  transform: translateY(-2px);
  filter: brightness(1.06);
  box-shadow: 0 10px 34px rgba(242, 42, 18, 0.5), 0 0 64px rgba(242, 42, 18, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.24);
}

.bscan-btn--primary:hover:not(:disabled) .btn__arrow {
  transform: translateX(4px);
}

.bscan-btn--secondary {
  color: var(--fb-white);
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.18);
}

.bscan-btn--secondary:hover:not(:disabled) {
  border-color: var(--fb-red);
  color: var(--fb-red);
}

.bscan-btn--ghost {
  color: var(--fb-gray);
  background: transparent;
  border: 1px solid transparent;
  padding: 0.9rem 1.25rem;
}

.bscan-btn--ghost:hover:not(:disabled) {
  color: var(--fb-white);
}

/* Progress + step counter */

.bscan-progress {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.bscan-progress__label {
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fb-gray);
}

.bscan-progress__track {
  position: relative;
  width: 100%;
  height: 3px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 999px;
  overflow: hidden;
}

.bscan-progress__fill {
  position: absolute;
  inset: 0;
  width: 0%;
  background: linear-gradient(90deg, var(--fb-red), #ff6a3f);
  border-radius: 999px;
  transition: width 0.4s var(--ease-out);
}

/* Question */

.bscan-question__title {
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  font-weight: var(--weight-bold);
  line-height: 1.35;
}

.bscan-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 0.75rem;
}

.bscan-option {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.9rem 1.1rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 0.25s ease, background-color 0.25s ease;
}

.bscan-option:hover {
  border-color: rgba(242, 42, 18, 0.4);
  background: rgba(255, 255, 255, 0.05);
}

.bscan-option.is-selected {
  border-color: var(--fb-red);
  background: rgba(242, 42, 18, 0.1);
}

.bscan-option__input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.bscan-option__input:focus-visible ~ .bscan-option__radio {
  outline: 2px solid var(--fb-red);
  outline-offset: 2px;
}

.bscan-option__radio {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.3);
  transition: border-color 0.25s ease;
}

.bscan-option.is-selected .bscan-option__radio {
  border-color: var(--fb-red);
  border-width: 5px;
  box-shadow: 0 0 8px rgba(242, 42, 18, 0.6);
}

.bscan-option__text {
  font-size: 0.9375rem;
  color: var(--fb-white);
}

.bscan-question__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.5rem;
}

.bscan-question__nav-right {
  display: flex;
  gap: 0.75rem;
  margin-left: auto;
}

/* Results */

.bscan-results__header {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.bscan-result-score {
  position: relative;
  width: 108px;
  height: 108px;
  flex-shrink: 0;
}

.bscan-result-score__ring {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.bscan-result-score__track {
  fill: none;
  stroke: rgba(244, 242, 237, 0.1);
  stroke-width: 7;
}

.bscan-result-score__fill {
  fill: none;
  stroke: var(--fb-red);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-dasharray: 326.7;
  stroke-dashoffset: 326.7;
  filter: drop-shadow(0 0 6px rgba(242, 42, 18, 0.75));
  transition: stroke-dashoffset 1s var(--ease-out);
}

.bscan-result-score__value {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1;
  font-size: 1.75rem;
  font-weight: var(--weight-bold);
}

.bscan-result-score__value small {
  font-size: 0.625rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.04em;
  color: var(--fb-gray);
  margin-top: 0.2rem;
}

.bscan-results__intro {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.bscan-results__ready {
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  font-weight: var(--weight-bold);
}

.bscan-results__level {
  display: inline-flex;
  align-self: flex-start;
  font-size: 0.6875rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fb-red);
  padding: 0.25rem 0.7rem;
  border: 1px solid rgba(242, 42, 18, 0.35);
  border-radius: 999px;
}

.bscan-results__summary {
  font-size: 0.9375rem;
  color: var(--fb-gray);
  line-height: 1.6;
}

.bscan-section-title {
  font-size: 0.75rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fb-white);
  margin-bottom: 1rem;
}

.bscan-areas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.25rem 2rem;
}

.bscan-area {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.bscan-area__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: 0.8125rem;
}

.bscan-area__name {
  color: var(--fb-white);
  font-weight: var(--weight-regular);
}

.bscan-area__value {
  color: var(--fb-gray);
  font-variant-numeric: tabular-nums;
}

.bscan-area__bar {
  position: relative;
  height: 5px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 999px;
  overflow: hidden;
}

.bscan-area__bar-fill {
  position: absolute;
  inset: 0;
  width: 0%;
  background: linear-gradient(90deg, var(--fb-red), #ff6a3f);
  border-radius: 999px;
  transition: width 1s var(--ease-out);
}

.bscan-lists {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 2rem;
}

.bscan-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.bscan-list__item {
  position: relative;
  padding-left: 1.1rem;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--fb-gray);
}

.bscan-list__item::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--fb-red);
}

.bscan-list--strengths .bscan-list__item::before {
  background: #3ddc84;
}

.bscan-roadmap {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
}

.bscan-roadmap__card {
  padding: 1.25rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.bscan-roadmap__index {
  font-size: 0.6875rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.08em;
  color: var(--fb-red);
}

.bscan-roadmap__title {
  font-size: 0.9375rem;
  font-weight: var(--weight-bold);
  line-height: 1.4;
}

.bscan-roadmap__tags {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.bscan-tag-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: 0.6875rem;
}

.bscan-tag-row__label {
  color: var(--fb-gray);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.bscan-tag-row__value {
  font-weight: var(--weight-bold);
  letter-spacing: 0.06em;
}

.bscan-tag-row__value.is-high { color: var(--fb-red); }
.bscan-tag-row__value.is-medium { color: #ffb648; }
.bscan-tag-row__value.is-low { color: #3ddc84; }

.bscan-services {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.bscan-service-pill {
  font-size: 0.8125rem;
  color: var(--fb-white);
  padding: 0.5rem 1rem;
  background: rgba(242, 42, 18, 0.08);
  border: 1px solid rgba(242, 42, 18, 0.3);
  border-radius: 999px;
}

/* Lead form */

.bscan-leadform {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.bscan-leadform__title {
  font-size: clamp(1.1rem, 2.2vw, 1.35rem);
  font-weight: var(--weight-bold);
  margin-bottom: 0.4rem;
}

.bscan-leadform__body {
  font-size: 0.9375rem;
  color: var(--fb-gray);
  line-height: 1.6;
}

.bscan-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}

.bscan-field {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.bscan-field--full {
  grid-column: 1 / -1;
}

.bscan-field label {
  font-size: 0.6875rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fb-gray);
}

.bscan-field input {
  background: rgba(0, 0, 0, 0.22);
  border: 1px solid rgba(244, 242, 237, 0.12);
  border-radius: 3px;
  padding: 0.65rem 0.8rem;
  font-family: var(--font);
  font-size: 0.9375rem;
  color: var(--fb-white);
  transition: border-color 0.3s ease, background-color 0.3s ease;
}

.bscan-field input::placeholder {
  color: var(--fb-gray);
}

.bscan-field input:focus {
  outline: none;
  border-color: var(--fb-red);
  background: rgba(0, 0, 0, 0.32);
}

.bscan-consent {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: 0.8125rem;
  color: var(--fb-gray);
  line-height: 1.5;
}

.bscan-consent input {
  margin-top: 0.2rem;
  accent-color: var(--fb-red);
  flex-shrink: 0;
}

.bscan-form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
}

/* Submission failure only -- kept out of normal flow (hidden by default)
   so it never reserves blank space while nothing has gone wrong. Shares
   the [hidden] specificity pattern already used elsewhere in this file
   ([hidden]{display:none} vs. an author display rule at equal
   specificity), so the override is written the same defensive way. */
.bscan-form-error {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: #ff8a75;
  background: rgba(242, 42, 18, 0.1);
  border: 1px solid rgba(242, 42, 18, 0.3);
  border-radius: 8px;
  padding: 0.75rem 1rem;
}

.bscan-form-error[hidden] {
  display: none;
}

.bscan-privacy-note {
  font-size: 0.75rem;
  color: var(--fb-gray);
  opacity: 0.75;
  line-height: 1.5;
}

/* Confirmation */

.bscan-confirmation {
  text-align: center;
  align-items: center;
  padding-block: clamp(2rem, 8vh, 5rem);
  gap: 1.25rem;
}

.bscan-confirmation__icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: 1px solid rgba(242, 42, 18, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--fb-red);
  font-size: 1.75rem;
}

.bscan-confirmation__title {
  font-size: clamp(1.35rem, 2.8vw, 1.75rem);
  font-weight: var(--weight-bold);
}

.bscan-confirmation__body {
  font-size: 0.9375rem;
  color: var(--fb-gray);
  line-height: 1.6;
  max-width: 440px;
}

/* Short laptop/tablet viewports -- shrink the intro's own spacing and
   logo progressively before ever falling back to an internal scrollbar.
   Height-based, so it applies across every width tier (a small laptop
   window is still "desktop" width-wise but can easily be under 800px
   tall). Only touches the intro screen's own elements; the taller
   questions/results/lead-form screens keep relying on
   .bscan-modal__body's normal overflow-y: auto. */
@media (max-height: 800px) {
  .bscan-intro {
    gap: 1.1rem;
  }

  .bscan-intro__logo {
    width: clamp(90px, 8vw, 108px);
  }

  .bscan-intro__features {
    padding-top: 0.85rem;
  }
}

@media (max-height: 700px) {
  .bscan-modal__body {
    padding-top: clamp(1rem, 2vw, 1.375rem);
    padding-bottom: clamp(1rem, 2vw, 1.375rem);
  }

  .bscan-intro {
    gap: 0.85rem;
  }

  .bscan-intro__logo {
    width: clamp(78px, 7vw, 92px);
  }

  .bscan-intro__features {
    padding-top: 0.6rem;
  }

  .bscan-intro__feature-icon {
    width: 28px;
    height: 28px;
  }
}

/* ------------------------------------------------------------------ */
/* Tablet                                                               */
/* ------------------------------------------------------------------ */

@media (min-width: 769px) and (max-width: 1024px) {
  .nav__logo-img {
    width: 68px;
  }

  body.portfolio-active .nav__logo-img {
    width: 42px;
  }

  .works__fixed-ui {
    width: clamp(190px, 22vw, 210px);
    top: 118px;
  }

  .works__heading-title {
    font-size: clamp(1.75rem, 4vw, 2.25rem);
  }

  /* Business Scan's own tablet/iPad Pro composition lives in its
     dedicated block below (769px-1366px) instead of here, since it needs
     to reach further than this block's 1024px ceiling. */

  .bscan-modal__window {
    width: min(95vw, 900px);
    height: auto;
    max-height: 90vh;
  }

  .bscan-intro__logo {
    width: clamp(95px, 12vw, 110px);
  }

  .bscan-fields {
    grid-template-columns: 1fr;
  }

  .bscan-field--full {
    grid-column: 1;
  }
}

/* ------------------------------------------------------------------ */
/* Business Scan -- Tablet / iPad Pro (769px-1366px)                   */
/* ------------------------------------------------------------------ */
/* A genuine two-column tablet composition, not the general Tablet
   block's stacked single column (which read as a compressed desktop
   layout): left copy keeps a real 44% column instead of full width,
   the score panel sits beside it at a fixed compact size instead of
   dropping full-width below, and the feature strip loses its card
   chrome to sit as a slim row directly under the content instead of a
   separate boxed section. One continuous range (rather than several
   stepped breakpoints) so it scales smoothly via clamp() from 11"
   portrait through 12.9" landscape; extends past the general Tablet
   block's 1024px ceiling since 1112/1180/1194/1366 (this section's own
   target widths) all exceed it. Desktop (>1366px) and mobile (<=768px)
   are untouched -- this band sits strictly between them. */
@media (min-width: 769px) and (max-width: 1366px) {
  .business-scan-hero {
    min-height: auto;
    /* Top padding is deliberately flat (not vw-scaled like the other
       sides) -- it exists to clear the fixed .nav bar (~119px tall,
       constant across this whole range, not something that scales with
       viewport width), not to echo the hero's own proportions. Without
       it the secondary logo below renders inside the nav's own fixed
       footprint, crowding against the nav's logo in the same corner. */
    padding: 9rem clamp(2rem, 4vw, 3rem) clamp(2.5rem, 4vw, 4rem);
  }

  .business-scan-content {
    grid-template-columns: minmax(300px, 44%) minmax(0, 1fr);
    column-gap: clamp(28px, 3.5vw, 56px);
    row-gap: 1.5rem;
    align-items: center;
  }

  .business-scan-left {
    grid-column: 1;
    grid-row: 1;
    max-width: 100%;
  }

  /* Secondary brand mark above the eyebrow -- tablet's own size band
     (110-130px), distinct from mobile's smaller 90-110px logo. */
  .business-scan-mobile-logo {
    display: block;
    width: clamp(110px, 9vw, 130px);
    height: auto;
    margin: 0 0 1rem;
  }

  .business-scan-heading {
    font-size: clamp(2.625rem, 4vw, 3.375rem);
    line-height: 1.06;
    max-width: 22ch;
    margin-bottom: 1.25rem;
  }

  .business-scan-sub {
    font-size: clamp(1rem, 0.7rem + 1.1vw, 1.125rem);
    max-width: 40ch;
    margin-bottom: 1.75rem;
  }

  .business-scan-cta {
    width: auto;
    min-width: 220px;
    max-width: 280px;
    justify-content: center;
    margin-bottom: 1rem;
  }

  /* Right panel: kept at its own compact width instead of stretched to
     fill the 56% column, and pulled up off dead-vertical-center so it
     reads as connected to the background scene behind it rather than
     hanging low in empty space. */
  .business-scan-hud {
    grid-column: 2;
    grid-row: 1;
    width: clamp(320px, 30vw, 380px);
    max-width: 100%;
    justify-self: end;
    align-self: center;
    margin-top: -2rem;
  }

  .bscan-panel {
    padding: 1.4rem 1.4rem 1.25rem;
  }

  .bscan-panel__top {
    margin-bottom: 1.1rem;
  }

  .bscan-score-row {
    gap: 1rem;
    margin-bottom: 1.1rem;
  }

  .bscan-hud-score {
    width: 66px;
    height: 66px;
  }

  .bscan-hud-score__value {
    font-size: 1.2rem;
  }

  .bscan-panel__divider {
    margin-bottom: 1rem;
  }

  .bscan-opp-row {
    padding: 0.55rem 0;
  }

  /* Compact horizontal row directly under the content zone -- same
     3-column icon+copy layout as desktop's .bscan-feature, just without
     the enclosing card (background/border/blur/radius) that made it
     read as a separate boxed section, and with tighter internal padding
     so it doesn't add unnecessary section height. */
  .business-scan-features {
    grid-column: 1 / -1;
    grid-row: 2;
    background: transparent;
    border: none;
    border-top: 1px solid rgba(244, 242, 237, 0.14);
    border-radius: 0;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    margin-top: 0.25rem;
  }

  .bscan-feature {
    flex: 1 1 0;
    min-width: 0;
    padding: 0.85rem 1.25rem;
  }

  .bscan-feature__icon {
    width: 32px;
    height: 32px;
  }

  .bscan-feature__icon svg {
    width: 15px;
    height: 15px;
  }

  .bscan-feature__title {
    font-size: 0.8125rem;
  }

  .bscan-feature__desc {
    font-size: 0.6875rem;
  }
}

/* Landscape iPad Pro (short viewport height, paired with the WhatsApp
   button's own shrink further down): the gap between the CTA and the
   benefit row is otherwise only ~38px here, narrower than even the
   shrunk 46px button needs to sit in without touching either -- a
   further, height-scoped widening of the row-gap and CTA's own bottom
   margin (portrait tablet's tighter spacing above is left alone) opens
   that gap enough to fit it. */
@media (min-width: 769px) and (max-width: 1366px) and (max-height: 900px) {
  .business-scan-content {
    row-gap: 2rem;
  }

  .business-scan-cta {
    margin-bottom: 1.5rem;
  }
}

/* ------------------------------------------------------------------ */
/* Mobile                                                               */
/* ------------------------------------------------------------------ */

@media (max-width: 768px) {
  /* Compact global mobile header, consistent across every section since
     .nav is one shared fixed element -- target ~60-72px total height
     (was ~120px last pass): 0.75rem padding + a 44px-wide logo. */
  .nav {
    padding: 0.75rem 1.25rem;
  }

  /* Premium dark glass backdrop -- sits behind .nav__logo/.nav__links (a
     plain sibling at z-index:-1, so it never interacts with .nav__links'
     own mix-blend-mode:difference) so scrolled-under content (e.g. Process
     text) is softened instead of creating visual noise under the logo/CTA.
     Mobile/tablet only -- desktop nav gets no visible background (the
     position:absolute layout fix above is unconditional, this visual
     treatment is not). */
  .nav__backdrop {
    background: linear-gradient(to bottom, rgba(11, 8, 8, 0.82), rgba(11, 8, 8, 0.58));
    backdrop-filter: blur(16px) saturate(115%);
    -webkit-backdrop-filter: blur(16px) saturate(115%);
    border-bottom: 1px solid rgba(244, 242, 237, 0.07);
  }

  .nav__links a:not(.nav__cta) {
    display: none;
  }

  .nav__menu-toggle {
    display: flex;
    order: -1;
    margin-right: 0.25rem;
  }

  .nav__mobile-menu:not([hidden]) {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: 100%;
    left: 0;
    width: 100%;
    padding: 0.5rem 1.5rem 1.25rem;
    background: rgba(11, 8, 8, 0.92);
    backdrop-filter: blur(16px) saturate(115%);
    -webkit-backdrop-filter: blur(16px) saturate(115%);
    border-bottom: 1px solid rgba(244, 242, 237, 0.07);
  }

  .nav__mobile-menu a {
    padding: 0.9rem 0;
    font-size: 0.9375rem;
    font-weight: var(--weight-regular);
    letter-spacing: 0.02em;
    color: var(--fb-white);
    border-top: 1px solid rgba(244, 242, 237, 0.08);
  }

  .nav__mobile-menu a:first-child {
    border-top: none;
  }

  /* HABLEMOS: compact but stays within the 42-46px comfortable tap
     range (smaller font + tighter padding than the previous pass). */
  .nav__cta {
    padding: 0.7rem 1.25rem;
    font-size: 0.75rem;
  }

  .nav__lang-btn {
    padding: 0.5rem 0.25rem;
  }

  /* .nav__logo-img had no <=768px override at all, so mobile kept the
     full 106px desktop width while the 769-1024px tablet query already
     shrinks it to 68px -- backwards (phones got the biggest logo).
     44px keeps it within the 40-52px compact target. */
  .nav__logo-img {
    width: 44px;
    flex-shrink: 0;
  }

  body.portfolio-active .nav__logo-img {
    width: 36px;
  }

  /* .nav is flex; .nav__logo/.nav__logo-img have no flex-shrink:0 of
     their own, so adding the 44px menu toggle to .nav__links (still at
     its base 2.5rem/40px gap) left too little room and the flex layout
     shrank the logo down to ~12px to compensate. flex-shrink:0 above
     stops that; tightening the gap here is what actually makes room for
     it instead of just moving the squeeze onto .nav__links' own content. */
  .nav__links {
    gap: 0.5rem;
  }

  .hero__content {
    padding: 0 1.25rem;
  }

  /* Base clamp's 2.2rem floor (35.2px) makes every one of the 3 manual
     .hero__line phrases wrap to 2 physical lines inside their reveal
     masks at mobile widths (e.g. "EXPERIENCIAS QUE CONECTAN." at 26
     chars vs ~17 chars/line capacity) -- 6 visual lines instead of the
     3 the design/animation is built for. Not a clipping bug (the masks
     are overflow:hidden with auto height, so nothing gets cut off), but
     exactly the "giant heading wrapping into 6-8 lines" anti-pattern.
     Lowering just the floor keeps tablet/desktop (already fine) untouched. */
  .hero__heading {
    font-size: clamp(1.75rem, 6vw, 2.4rem);
  }

  .hero__sub {
    text-align: center;
    text-align-last: auto;
  }

  /* .hero__content is vertically centered in a 100vh flex box with no
     collision awareness of its own height -- on short mobile viewports
     (~650px and under) the CTA's bottom edge can land right on top of
     this indicator's fixed bottom:2.5rem. Mobile users already know to
     swipe, so this desktop-era "scroll down" hint is dropped here rather
     than fought over with vertical-rhythm math for every phone height. */
  .hero__scroll-indicator {
    display: none;
  }

  /* top: the fixed global header measures ~70px tall on mobile (44px
     logo + its 2x0.75rem padding) -- +16px keeps SELECTED WORK clear of
     it instead of trapped underneath. gap widened so the filter row reads
     as clearly below the title rather than crowding it. */
  .works__fixed-ui {
    top: 86px;
    left: 0;
    width: 100%;
    height: auto;
    flex-direction: column;
    justify-content: flex-start;
    gap: 1.25rem;
    padding: 0 1.25rem 0.85rem;
  }

  .works__heading-eyebrow {
    display: none;
  }

  .works__heading-title {
    font-size: 1.05rem;
  }

  .works__categories {
    flex-direction: row;
    overflow-x: auto;
    gap: 1.1rem;
    margin-top: 0;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Bare hidden-scrollbar overflow gives zero hint this row scrolls --
       same fade-edge affordance already used for .ds-solutions-marquee,
       just one-sided (right only) since this scroll starts at its left
       edge with the active filter already visible there, unlike that
       looping marquee which always has content on both sides. */
    -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 88%, transparent 100%);
    mask-image: linear-gradient(90deg, #000 0%, #000 88%, transparent 100%);
  }

  .works__categories::-webkit-scrollbar {
    display: none;
  }

  .works__category {
    white-space: nowrap;
    flex-shrink: 0;
  }

  /* Mobile no longer uses the desktop pinned/scroll-jacked horizontal
     track at all (buildWorksTrack() in main.js skips creating that
     ScrollTrigger below 769px) -- vertical finger movement must keep
     scrolling the page normally, only horizontal movement should browse
     cards, which a GSAP-scrubbed pin can't do on touch without fighting
     the user's own scroll. .works__container/.works__fixed-ui/.works__viewport
     all switch from the desktop absolute-positioned/100vh-pinned stack to
     plain normal flow (fixed-ui, then viewport, stacked top to bottom) --
     this also means the previous fixed top-offset calibration (tied to
     header height) is no longer needed at all. */
  .works__container {
    height: auto;
    overflow: visible;
  }

  .works__fixed-ui {
    position: static;
  }

  .works__viewport {
    position: static;
    left: auto;
    top: auto;
    right: auto;
    bottom: auto;
    height: auto;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-x pan-y;
    padding: 1.5rem 0 2.5rem;
    scrollbar-width: none;
  }

  .works__viewport::-webkit-scrollbar {
    display: none;
  }

  /* .works__wrapper still inherited desktop's --works-gap/--works-edge/
     --works-lead (80px/80px/40-90px) here -- on a 375px viewport that
     pushed the next card almost entirely off-screen, accidentally hiding
     the "peek of the next card" the swipe carousel is supposed to show,
     rather than an intentional single-card-only view. */
  .works__wrapper {
    height: auto;
    align-items: stretch;
    padding: 0 1.25rem;
    gap: 0.875rem;
  }

  /* 85vw (within the requested 82-90vw range) with scroll-snap-align so
     each card snaps cleanly into view, and enough of the next card peeks
     in at the edge (100vw - 85vw - gap) to suggest "there's more to the
     right" without needing a separate visual hint. */
  .work-item {
    width: 85vw;
    scroll-snap-align: start;
  }

  .works__end,
  .works__view-all {
    scroll-snap-align: start;
  }

  .studio {
    padding: 2.5rem 1.5rem 4rem;
  }

  /* Compact editorial index: meta row (Creative Disciplines / 01-06) +
     a 3-column grid of the 6 disciplines, replacing the desktop flex
     row. margin-top is the actual controllable gap after the sticky
     narrative releases -- ~48px, the requested 40-56px range. */
  .studio__labels {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.85rem 1rem;
    max-width: none;
    margin: 3rem 1.25rem 0;
    padding: 1.25rem 0 1.75rem;
  }

  .studio__labels-meta {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.5rem;
    font-size: 0.625rem;
    font-weight: var(--weight-light);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--fb-gray);
    opacity: 0.7;
  }

  .studio__label {
    font-size: 0.6875rem;
  }

  .studio__label.is-active {
    color: var(--fb-white);
  }

  .studio__label.is-active::after {
    content: '';
    display: inline-block;
    width: 4px;
    height: 4px;
    margin-left: 0.4em;
    border-radius: 50%;
    background: var(--fb-red);
    vertical-align: middle;
  }

  /* Root cause of the mobile "video disappears" bug: .capabilities__pin
     has no explicit width, so it (and the video/overlay/dots absolutely
     positioned inside it) inherited the section's own horizontal padding
     as its content-box width -- inset ~24px on each side instead of a
     true full-bleed cinematic background. Fix: drop the section's own
     horizontal padding on mobile and move it to .capabilities__header
     instead (the only child that actually needs it -- .capabilities__door
     already sizes itself off the viewport via width:min(92vw,420px), so
     it stays safely inset regardless of the section's own padding). */
  .capabilities {
    padding: 5rem 0 6rem;
  }

  .capabilities__header {
    padding: 0 1.5rem;
  }

  .capabilities__door {
    width: min(92vw, 420px);
  }

  /* Same video opacity/filter as desktop -- only a subtle extra bump on
     the shared overlay (not the video itself) for mobile readability. */
  .capabilities__visual-overlay {
    background: rgba(11, 8, 8, 0.4);
  }

  .process {
    padding: 6rem 1.5rem;
  }

  .process__list {
    padding-left: 2rem;
  }

  .process-step::before {
    left: -2.5rem;
  }

  .lab {
    padding: 6rem 1.5rem;
  }

  .lab-entry {
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
      "index category category"
      "title title title"
      "date date arrow";
    row-gap: 0.5rem;
    column-gap: 0.75rem;
  }

  .lab-entry__index {
    grid-area: index;
  }

  .lab-entry__title {
    grid-area: title;
  }

  .lab-entry__arrow {
    grid-area: arrow;
  }

  .lab-entry__category {
    grid-area: category;
    font-size: 0.6875rem;
  }

  .lab-entry__date {
    grid-area: date;
  }

  /* Toggle now sits directly under the heading (instead of the full
     01-06 list/entries) -- the desktop 5rem gap assumed the list was the
     very next thing on the page, so it reads as a large empty gap here. */
  .process__heading,
  .lab__heading {
    margin-bottom: 1.75rem;
  }

  /* Mobile-only accordion trigger. A flat bracket-style bar rather than
     the site's rounded .nav__cta pill -- reads as "reveal a list" rather
     than "take an action", matching the requested
     "[ VER PROCESO   + ]" treatment instead of a generic pill button. */
  .process__accordion-toggle,
  .lab__accordion-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    gap: 1rem;
    padding: 0.9rem 1.25rem;
    background: rgba(244, 242, 237, 0.03);
    border: 1px solid rgba(244, 242, 237, 0.22);
    border-radius: 14px;
    color: var(--fb-white);
    font-size: 0.75rem;
    font-weight: var(--weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    appearance: none;
    cursor: pointer;
    transition: border-color 0.3s ease, background 0.3s ease;
  }

  .process__accordion-toggle:hover,
  .process__accordion-toggle:focus-visible,
  .lab__accordion-toggle:hover,
  .lab__accordion-toggle:focus-visible {
    border-color: rgba(242, 42, 18, 0.5);
    background: rgba(244, 242, 237, 0.06);
  }

  .process__accordion-toggle:active,
  .lab__accordion-toggle:active {
    background: rgba(244, 242, 237, 0.1);
  }

  .process__accordion-icon,
  .lab__accordion-icon {
    color: var(--fb-red);
    font-size: 1rem;
    font-weight: var(--weight-bold);
    line-height: 1;
  }

  /* Native height-transition accordion body (see initMobileAccordion() in
     main.js): overflow:hidden clips the 01-06 list/entries at whatever
     pixel height JS is animating through; padding-top (not margin-top)
     provides the gap below the trigger only once expanded, since padding
     -- unlike margin -- is inside the box overflow:hidden/height:0 clips
     away while collapsed. JS releases height to auto once open, so later
     reflows (orientation change, a longer translation) aren't stuck at a
     stale pixel value. */
  .process__body,
  .lab__list {
    overflow: hidden;
    padding-top: 1.75rem;
    transition: height 0.4s var(--ease-out);
  }

  /* Mobile: HUD panels dropped entirely (illustrative-only content, not
     worth the space against the core headline/CTA on a small screen) and
     the overlay strengthened + evened out, since text now spans the full
     width instead of just the left half -- a left-to-right gradient tuned
     for a two-column layout would leave the right side under-darkened
     once there is no HUD there to occupy it. */
  .business-scan-hero {
    min-height: auto;
    /* 4rem, down from 5rem -- with the logo now sitting above the
       eyebrow too, 80px of top padding before anything appeared read as
       an unnecessarily large empty gap. */
    padding: 4rem 1.5rem;
  }

  .business-scan-overlay {
    background: rgba(11, 8, 8, 0.72);
  }

  .business-scan-gradient {
    background: linear-gradient(180deg, rgba(11, 8, 8, 0.4) 0%, rgba(11, 8, 8, 0.8) 55%, rgba(11, 8, 8, 0.94) 100%);
  }

  .business-scan-content {
    grid-template-columns: 1fr;
    row-gap: 2.5rem;
  }

  .business-scan-left {
    max-width: 100%;
  }

  /* Introduces the section above the headline -- compact, not a repeat
     of the modal's own (larger) logo treatment. Centered via
     margin-inline:auto on the logo alone -- .business-scan-left and
     everything else inside it (headline/paragraph/CTA/tags) stays
     left-aligned, margin-auto centering a block element doesn't depend
     on the parent's text-align. Original SVG colors/proportions untouched. */
  .business-scan-mobile-logo {
    display: block;
    width: clamp(90px, 24vw, 110px);
    height: auto;
    margin: 0 auto 1.25rem;
  }

  .business-scan-heading {
    font-size: clamp(1.6rem, 7vw, 2rem);
  }

  .business-scan-hud {
    display: none;
  }

  .business-scan-features {
    flex-direction: column;
    margin-top: 2rem;
  }

  /* Root cause of the oversized mobile cards: base rule's
     flex: 1 1 260px sets a 260px flex-basis meant for WIDTH in the
     desktop row layout. .business-scan-features switches to
     flex-direction: column just above, so that same 260px basis applies
     to HEIGHT instead -- every card was rendering ~260px tall regardless
     of its actual (much shorter) content. Same bug class already found
     and fixed in the Business Scan modal's own feature row this session. */
  .bscan-feature {
    flex: none;
    gap: 0.75rem;
    border-left: none;
    border-top: 1px solid rgba(244, 242, 237, 0.1);
    padding: 1.1rem 1.25rem;
  }

  .bscan-feature:first-child {
    border-top: none;
  }

  .bscan-feature__icon {
    width: 32px;
    height: 32px;
  }

  .bscan-feature__icon svg {
    width: 16px;
    height: 16px;
  }

  .business-scan-cta {
    width: 100%;
    justify-content: center;
  }

  .contact__field--full {
    grid-column: 1;
  }

  .contact__footer {
    flex-direction: column;
    gap: 1.5rem;
    align-items: flex-start;
  }

  /* Near-fullscreen on mobile per spec -- no floating card, no gutter. */
  .bscan-modal-backdrop {
    padding: 0;
  }

  .bscan-modal__window {
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    border-radius: 0;
    border-left: none;
    border-right: none;
  }

  .bscan-modal__header {
    padding: 1rem 1.25rem;
  }

  .bscan-modal__body {
    padding: 1.5rem 1.25rem 2.5rem;
  }

  .bscan-intro__logo {
    width: clamp(80px, 24vw, 95px);
  }

  .bscan-fields {
    grid-template-columns: 1fr;
  }

  .bscan-field--full {
    grid-column: 1;
  }

  .bscan-question__nav {
    flex-wrap: wrap;
  }

  .bscan-question__nav-right {
    width: 100%;
    justify-content: space-between;
  }

  .bscan-btn {
    flex: 1;
  }

  .bscan-intro__features {
    flex-direction: column;
  }

  .bscan-intro__feature {
    flex: none;
    border-left: none;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    padding: 0.85rem 0;
  }

  .bscan-intro__feature:first-child {
    border-top: none;
  }
}

/* Process/Lab accordion: disable the height transition under reduced
   motion. Belt-and-suspenders with the JS-level reduceMotion branch in
   initMobileAccordion() (main.js), which already skips straight to the
   end state instead of animating through scrollHeight. */
@media (max-width: 768px) and (prefers-reduced-motion: reduce) {
  .process__body,
  .lab__list {
    transition: none;
  }
}

/* ------------------------------------------------------------------ */
/* Digital Systems popup (Capabilities / 02 Digital Experiences)       */
/* Desktop only for now -- clamp()/vw/% throughout so a mobile pass    */
/* later doesn't need hardcoded positions reworked from scratch.       */
/* ------------------------------------------------------------------ */

html.digital-systems-modal-lock,
html.digital-systems-modal-lock body {
  overflow: hidden !important;
}

/* ------------------------------------------------------------------ */
/* Portfolio gallery / lightbox                                        */
/* ------------------------------------------------------------------ */

html.portfolio-gallery-lock,
html.portfolio-gallery-lock body {
  overflow: hidden !important;
}

.portfolio-gallery-backdrop {
  position: fixed;
  inset: 0;
  z-index: 550;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(4, 3, 3, 0.92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.portfolio-gallery-backdrop.is-open {
  opacity: 1;
  pointer-events: auto;
}

.portfolio-gallery {
  position: relative;
  width: 100%;
  height: 100%;
  max-width: 1400px;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  transform: scale(0.98);
  transition: transform 0.35s var(--ease-out);
}

.portfolio-gallery-backdrop.is-open .portfolio-gallery {
  transform: scale(1);
}

.portfolio-gallery__close {
  position: absolute;
  top: -6px;
  right: 0;
  z-index: 2;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(244, 242, 237, 0.18);
  border-radius: 50%;
  color: var(--fb-white);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.3s ease, color 0.3s ease, transform 0.3s ease;
}

.portfolio-gallery__close:hover {
  border-color: var(--fb-red);
  color: var(--fb-red);
  transform: rotate(90deg);
}

.portfolio-gallery__stage {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

.portfolio-gallery__image-wrap {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.portfolio-gallery__image {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border: 1px solid rgba(244, 242, 237, 0.1);
}

.portfolio-gallery__nav {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(11, 8, 8, 0.5);
  border: 1px solid rgba(244, 242, 237, 0.14);
  border-radius: 50%;
  color: var(--fb-white);
  font-size: 1.1rem;
  cursor: pointer;
  transition: border-color 0.3s ease, background-color 0.3s ease, transform 0.3s ease;
}

.portfolio-gallery__nav:hover {
  border-color: rgba(242, 42, 18, 0.5);
  background: rgba(242, 42, 18, 0.12);
}

.portfolio-gallery__nav[hidden] {
  display: none;
}

.portfolio-gallery__nav--prev:hover {
  transform: translateX(-3px);
}

.portfolio-gallery__nav--next:hover {
  transform: translateX(3px);
}

.portfolio-gallery__meta {
  flex-shrink: 0;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(244, 242, 237, 0.1);
}

.portfolio-gallery__info {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  min-width: 0;
}

.portfolio-gallery__number {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  color: var(--fb-red);
  letter-spacing: 0.08em;
  flex-shrink: 0;
}

.portfolio-gallery__title {
  font-size: 1.05rem;
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
  color: var(--fb-white);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.portfolio-gallery__service {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  color: var(--fb-gray);
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.portfolio-gallery__counter {
  flex-shrink: 0;
  font-size: 0.7rem;
  font-weight: var(--weight-light);
  color: var(--fb-gray);
  letter-spacing: 0.08em;
  font-family: monospace;
}

@media (max-width: 768px) {
  .portfolio-gallery-backdrop {
    padding: 1rem;
    padding-top: max(1rem, env(safe-area-inset-top));
  }

  .portfolio-gallery__close {
    top: 0;
    width: 36px;
    height: 36px;
  }

  .portfolio-gallery__stage {
    gap: 0.5rem;
  }

  .portfolio-gallery__nav {
    width: 36px;
    height: 36px;
  }

  .portfolio-gallery__info {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15rem;
  }

  .portfolio-gallery__title,
  .portfolio-gallery__service {
    max-width: 60vw;
  }
}

.digital-systems-backdrop {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4vh 2vw;
  background: rgba(0, 0, 0, 0.74);
  opacity: 0;
  pointer-events: none;
}

.digital-systems-backdrop.is-open {
  pointer-events: auto;
}

.digital-systems-modal__window {
  position: relative;
  width: min(92vw, 1500px);
  max-height: 88vh;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 20px;
  background: rgba(8, 8, 8, 0.96);
  overflow: hidden;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(242, 42, 18, 0.55) transparent;
}

.digital-systems-modal__window::-webkit-scrollbar {
  width: 6px;
}

.digital-systems-modal__window::-webkit-scrollbar-track {
  background: transparent;
  margin-block: 20px;
}

.digital-systems-modal__window::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, rgba(242, 42, 18, 0.75), rgba(242, 42, 18, 0.35));
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.06);
}

.digital-systems-modal__window::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, rgba(255, 90, 50, 0.9), rgba(242, 42, 18, 0.5));
}

.digital-systems-modal__controls {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.25rem 1.5rem;
  pointer-events: none;
}

.digital-systems-backdrop.is-open .digital-systems-modal__controls > * {
  pointer-events: auto;
}

.ds-control {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: rgba(8, 8, 8, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 999px;
  color: var(--fb-white);
  cursor: pointer;
  transition: border-color 0.3s ease, transform 0.3s ease, color 0.3s ease;
}

.ds-control:hover,
.ds-control:focus-visible {
  border-color: var(--fb-white);
  transform: scale(1.04);
}

.ds-control:hover .ds-control__icon,
.ds-control:focus-visible .ds-control__icon {
  color: var(--fb-red);
}

.ds-control--back {
  height: 52px;
  padding: 0 1.25rem 0 1rem;
  font-size: 0.8125rem;
  font-weight: var(--weight-regular);
  letter-spacing: 0.04em;
}

.ds-control__icon {
  font-size: 1.1rem;
  transition: color 0.3s ease;
}

.ds-control--close {
  width: 52px;
  height: 52px;
  justify-content: center;
  font-size: 1.5rem;
  line-height: 1;
}

.ds-control--close:hover,
.ds-control--close:focus-visible {
  color: var(--fb-red);
}

.digital-systems-modal__scene {
  position: relative;
  margin-top: -52px; /* pull content up under the sticky controls bar */
  padding-top: 1rem;
}

.ds-layer {
  position: absolute;
  pointer-events: none;
}

.ds-layer img {
  display: block;
  width: 100%;
  height: auto;
}

.ds-layer--bg {
  inset: 0;
  z-index: 0;
  opacity: 0.5;
}

.ds-layer--bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ds-layer--planet {
  top: 6%;
  right: -10%;
  width: min(46vw, 620px);
  z-index: 1;
  opacity: 0.55;
}

.ds-layer--glow {
  top: 10%;
  right: 4%;
  width: min(50vw, 680px);
  z-index: 2;
  opacity: 0.5;
  mix-blend-mode: screen;
}

.digital-systems-modal__body {
  position: relative;
  z-index: 4;
  display: grid;
  grid-template-columns: 33% 67%;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding: clamp(2.5rem, 5vw, 4.5rem) clamp(2rem, 5vw, 4rem) clamp(2rem, 4vw, 3rem);
  min-height: 56vh;
}

.digital-systems-modal__text {
  max-width: 400px;
  min-width: 0;
}

.digital-systems-modal__eyebrow {
  display: block;
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fb-red);
  margin-bottom: 1rem;
}

.digital-systems-modal__title {
  font-size: clamp(2.25rem, 3.6vw, 3.5rem);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tighter);
  color: var(--fb-white);
  line-height: 1.05;
  margin-bottom: 1.25rem;
}

.digital-systems-modal__copy {
  font-size: 1rem;
  line-height: 1.7;
  color: var(--fb-gray);
  max-width: 340px;
  margin-bottom: 1.75rem;
}

.digital-systems-modal__services {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 0.35rem;
}

.ds-service {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  gap: 11px;
  padding: 8px 14px 8px 8px;
  border-radius: 13px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(10, 10, 12, 0.58);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.03) inset,
    0 8px 24px rgba(0, 0, 0, 0.35);
  transition: border-color 0.28s ease, transform 0.28s ease, background-color 0.28s ease, box-shadow 0.28s ease;
}

.ds-service:hover,
.ds-service:focus-visible {
  border-color: rgba(255, 255, 255, 0.24);
  background: rgba(14, 14, 16, 0.68);
  transform: translateY(-1.5px);
}

.ds-service__icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 9px;
  background: linear-gradient(180deg, rgba(40, 20, 18, 0.72), rgba(18, 18, 22, 0.85));
  border: 1px solid rgba(255, 90, 45, 0.55);
  box-shadow:
    0 0 18px rgba(255, 80, 35, 0.18),
    0 0 0 1px rgba(255, 110, 70, 0.06) inset;
  color: var(--fb-red);
  transition: box-shadow 0.28s ease;
}

.ds-service:hover .ds-service__icon,
.ds-service:focus-visible .ds-service__icon {
  box-shadow:
    0 0 24px rgba(255, 80, 35, 0.3),
    0 0 0 1px rgba(255, 110, 70, 0.1) inset;
}

.ds-service__icon svg {
  width: 17px;
  height: 17px;
}

.ds-service__label {
  font-size: 0.84rem;
  font-weight: var(--weight-light);
  letter-spacing: 0.005em;
  line-height: 1;
  color: rgba(255, 255, 255, 0.82);
  white-space: nowrap;
  transition: color 0.28s ease;
}

.ds-service:hover .ds-service__label,
.ds-service:focus-visible .ds-service__label {
  color: var(--fb-white);
}

@media (max-width: 900px) {
  .ds-service {
    padding: 7px 12px 7px 7px;
    gap: 9px;
  }
}

/* This modal is commented elsewhere in this file as "Desktop only for
   now" but nothing actually stops it opening on a phone -- doing so stacks
   7x .ds-service + 8x .ds-solutions-marquee__item backdrop-filter:blur()
   layers (the marquee ones inside a continuously-looping animation) on
   top of the nav's own blur, ~15-17 simultaneous blur contexts from one
   tap. Dropping backdrop-filter and compensating with a touch more
   opacity keeps the same visual read without the compositing cost. */
@media (max-width: 768px) {
  .ds-service {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: rgba(10, 10, 12, 0.85);
  }
}

@media (max-width: 560px) {
  .digital-systems-modal__services {
    gap: 8px;
  }

  .ds-service {
    flex: 1 1 calc(50% - 8px);
    justify-content: flex-start;
  }

  .ds-service__label {
    white-space: normal;
  }
}

.digital-systems-modal__visual {
  position: relative;
  z-index: 4;
  width: 97%;
  min-width: 0;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Single pre-composited asset (laptop + all four floating panels already
   integrated by design) replaces the previous cluster of separately
   positioned layers. */
.ds-layer--composite {
  position: relative;
  width: clamp(620px, 68vw, 1040px);
  max-width: 100%;
}

.ds-layer--composite img {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 22px 34px rgba(0, 0, 0, 0.3));
}

.digital-systems-modal__solutions {
  position: relative;
  z-index: 4;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: rgba(255, 255, 255, 0.08);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.ds-solution {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  padding: 1.5rem 1.5rem 1.75rem;
  background: rgba(8, 8, 8, 0.96);
  transition: background 0.3s ease;
}

.ds-solution:hover {
  background: rgba(20, 12, 10, 0.96);
}

.ds-solution__index {
  font-size: 0.75rem;
  font-weight: var(--weight-light);
  color: var(--fb-red);
  letter-spacing: 0.05em;
  padding-top: 0.2rem;
}

.ds-solution__main {
  flex: 1;
  min-width: 0;
}

.ds-solution__title {
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--fb-white);
  margin-bottom: 0.4rem;
}

.ds-solution__desc {
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--fb-gray);
}

.ds-solution__arrow {
  flex-shrink: 0;
  color: var(--fb-gray);
  opacity: 0.6;
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.ds-solution:hover .ds-solution__arrow {
  opacity: 1;
  color: var(--fb-red);
  transform: translateX(3px);
}

.ds-solutions-marquee {
  display: none;
  position: relative;
  z-index: 4;
  overflow: hidden;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  padding: 1.1rem 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.ds-solutions-marquee__track {
  display: flex;
  align-items: center;
  gap: 12px;
  width: max-content;
  will-change: transform;
  animation: ds-solutions-marquee 16s linear infinite;
}

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

.ds-solutions-marquee__item {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(10, 10, 12, 0.6);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-size: 0.8rem;
  font-weight: var(--weight-light);
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
}

.ds-solutions-marquee__index {
  color: var(--fb-red);
  font-weight: var(--weight-light);
  font-size: 0.75rem;
  margin-right: 2px;
}

@media (max-width: 768px) {
  /* Same blur-stacking concern as .ds-service above, but this override
     has to live after .ds-solutions-marquee__item's own base rule
     (:5104) -- the earlier @media block this was first tried in sits
     before that base rule in source order, so the later unconditional
     rule was winning the cascade and the blur never actually left. */
  .ds-solutions-marquee__item {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: rgba(10, 10, 12, 0.85);
  }

  .digital-systems-modal__body {
    grid-template-columns: 1fr;
    gap: 1.75rem;
    padding: clamp(2rem, 8vw, 3rem) 1.5rem 1.5rem;
    min-height: 0;
  }

  .digital-systems-modal__visual {
    order: -1;
    width: 100%;
  }

  .ds-layer--composite {
    width: min(80vw, 420px);
  }

  .digital-systems-modal__text {
    max-width: 100%;
  }

  .digital-systems-modal__copy {
    max-width: 100%;
    text-align: justify;
  }

  .digital-systems-modal__solutions {
    display: none;
  }

  .ds-solutions-marquee {
    display: block;
  }
}

@media (prefers-reduced-motion: reduce) {
  .digital-systems-backdrop,
  .digital-systems-modal__window {
    transition: none;
  }

  .ds-solutions-marquee__track {
    animation: none;
  }

  .bscan-modal-backdrop {
    transition: none;
  }
}

/* ------------------------------------------------------------------ */
/* WhatsApp floating CTA                                                */
/* ------------------------------------------------------------------ */

/* Hidden by default -- initWhatsappCta() in main.js adds .is-visible only
   once the user has scrolled past the end of #hero, and removes it again
   on scrolling back in (scrolling itself is locked by body.is-loading
   until the intro finishes, so both conditions are satisfied by the time
   this can ever become true). This wrapper only handles that reveal;
   .whatsapp-cta__trigger below is the actual collapsed-circle/expanded-
   pill control. */
.whatsapp-cta {
  position: fixed;
  right: clamp(28px, 3vw, 36px);
  bottom: clamp(28px, 3vh, 36px);
  z-index: 80;
  opacity: 0;
  transform: translateY(12px);
  filter: blur(5px);
  pointer-events: none;
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out),
    filter 0.6s var(--ease-out);
}

.whatsapp-cta.is-visible {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
  pointer-events: auto;
}

/* Collapsed = a plain circle (width == height); expanding only grows
   `width`, so the icon -- pinned to a fixed-width flex slot -- never
   moves. overflow:hidden clips the separator/text/dot while collapsed
   instead of needing a second set of layout rules for that state. */
.whatsapp-cta__trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  height: 60px;
  width: 60px;
  padding: 0 1rem 0 0;
  border: 1px solid rgba(244, 242, 237, 0.14);
  border-radius: 999px;
  background: rgba(11, 8, 8, 0.72);
  backdrop-filter: blur(14px) saturate(115%);
  -webkit-backdrop-filter: blur(14px) saturate(115%);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.4);
  color: var(--fb-white);
  overflow: hidden;
  cursor: pointer;
  font-family: var(--font-primary);
  transition: width 0.4s var(--ease-out), border-color 0.35s ease,
    box-shadow 0.35s ease, background-color 0.35s ease;
}

.whatsapp-cta__trigger.is-expanded {
  width: 224px;
}

.whatsapp-cta__trigger:hover,
.whatsapp-cta__trigger:focus-visible {
  border-color: rgba(79, 189, 127, 0.4);
  background: rgba(11, 8, 8, 0.82);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45), 0 0 16px rgba(79, 189, 127, 0.1);
}

.whatsapp-cta__trigger:focus-visible {
  outline: 1px solid rgba(244, 242, 237, 0.5);
  outline-offset: 3px;
}

.whatsapp-cta__icon {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  flex-shrink: 0;
}

.whatsapp-cta__icon svg {
  width: 20px;
  height: 20px;
  fill: #4fbd7f;
}

.whatsapp-cta__separator,
.whatsapp-cta__text {
  opacity: 0;
  transition: opacity 0.2s ease;
}

.whatsapp-cta__trigger.is-expanded .whatsapp-cta__separator,
.whatsapp-cta__trigger.is-expanded .whatsapp-cta__text {
  opacity: 1;
  transition: opacity 0.25s ease 0.15s;
}

.whatsapp-cta__separator {
  width: 1px;
  height: 22px;
  flex-shrink: 0;
  background: rgba(244, 242, 237, 0.16);
}

.whatsapp-cta__text {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
  white-space: nowrap;
  text-align: left;
}

.whatsapp-cta__label {
  font-size: 0.8rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.01em;
}

.whatsapp-cta__number {
  font-size: 0.68rem;
  font-weight: var(--weight-light);
  color: var(--fb-gray);
  letter-spacing: 0.02em;
}

.whatsapp-cta__dot {
  width: 7px;
  height: 7px;
  flex-shrink: 0;
  margin-left: auto;
  border-radius: 50%;
  background: #4fbd7f;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.whatsapp-cta__trigger.is-expanded .whatsapp-cta__dot {
  opacity: 1;
  transition: opacity 0.25s ease 0.15s;
}

@media (max-width: 768px) {
  .whatsapp-cta {
    right: max(18px, env(safe-area-inset-right));
    bottom: max(20px, calc(18px + env(safe-area-inset-bottom)));
  }

  .whatsapp-cta__trigger {
    height: 56px;
    width: 56px;
  }

  .whatsapp-cta__trigger.is-expanded {
    width: 204px;
  }

  .whatsapp-cta__icon {
    width: 56px;
    height: 56px;
  }

  .whatsapp-cta__icon svg {
    width: 18px;
    height: 18px;
  }

  .whatsapp-cta__label {
    font-size: 0.76rem;
  }

  .whatsapp-cta__number {
    font-size: 0.64rem;
  }
}

/* Landscape iPad Pro (short viewport height: 11"/10.5"/Air land around
   768-834px tall, vs. portrait's 1024-1366px, and vs. 12.9" landscape's
   own 1024px -- max-height keeps this scoped to just the short ones).
   The Business Scan section's four-line headline (hard <br> breaks in
   the copy, not something this pass changes) plus its full content
   stack runs taller than these short viewports, so at the section's
   natural resting scroll position the fixed WhatsApp button's normal
   60px footprint lands on the benefit row -- there's a genuine but
   narrow (~60px) clear band between the CTA and the benefit row here,
   so the button shrinks to fit inside it instead of the row moving.
   (Global control, so this reaches every section at this viewport size,
   not just Business Scan -- harmless elsewhere, where there's already
   more clearance.) */
@media (min-width: 769px) and (max-width: 1366px) and (max-height: 900px) {
  .whatsapp-cta {
    bottom: 72px;
  }

  .whatsapp-cta__trigger,
  .whatsapp-cta__icon {
    width: 46px;
    height: 46px;
  }

  .whatsapp-cta__trigger.is-expanded {
    width: 190px;
  }

  .whatsapp-cta__icon svg {
    width: 17px;
    height: 17px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .whatsapp-cta {
    transition: opacity 0.3s ease;
  }
}

/* ------------------------------------------------------------------ */
/* Custom cursor (desktop with a mouse only)                           */
/* ------------------------------------------------------------------ */
/* initCustomCursor() in main.js only ever adds html.custom-cursor-active
   on a genuine (hover:hover) and (pointer:fine) match, so none of this
   ever shows on touch/tablet -- .custom-cursor also starts display:none
   unconditionally as a second, CSS-only guard independent of JS.

   Position is owned entirely by JS, written every animation frame as
   translate3d() on .custom-cursor__dot/__ring (never top/left, so this
   costs a compositor-only paint, not layout). Size/color/opacity state
   changes (hover, portfolio, scan, external) are ordinary CSS
   transitions on width/height/border-color/opacity -- deliberately not
   on transform, so they never fight the per-frame JS position update.
   Magnetic movement on target elements (see CURSOR_MAGNETIC_SELECTOR in
   main.js) works the same way -- JS lerps a small offset and writes
   translate3d() directly each frame, and never touches those elements'
   own `transition` property, so their existing hover transitions
   (background/border-color/box-shadow etc.) are untouched. */
.custom-cursor {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  pointer-events: none;
}

html.custom-cursor-active .custom-cursor {
  display: block;
}

@media (hover: hover) and (pointer: fine) {
  /* Native cursor only comes back for text fields and anything
     contenteditable -- everywhere else the dot/ring stand in for it. */
  html.custom-cursor-active,
  html.custom-cursor-active a,
  html.custom-cursor-active button {
    cursor: none;
  }

  html.custom-cursor-active input,
  html.custom-cursor-active textarea,
  html.custom-cursor-active select,
  html.custom-cursor-active [contenteditable] {
    cursor: auto;
  }
}

.custom-cursor__dot,
.custom-cursor__ring {
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 50%;
  opacity: 0;
}

.custom-cursor.is-visible .custom-cursor__dot,
.custom-cursor.is-visible .custom-cursor__ring {
  opacity: 1;
}

.custom-cursor__dot {
  width: 6px;
  height: 6px;
  background: var(--fb-red);
  transition: opacity 0.25s ease;
}

.custom-cursor__ring {
  width: 30px;
  height: 30px;
  border: 1px solid rgba(244, 242, 237, 0.45);
  box-shadow: 0 0 12px rgba(242, 42, 18, 0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.25s ease, width 0.35s var(--ease-out), height 0.35s var(--ease-out),
    border-color 0.3s ease, box-shadow 0.3s ease, background-color 0.3s ease;
}

.custom-cursor__label {
  font-family: var(--font-primary);
  font-size: 0.5625rem;
  font-weight: var(--weight-bold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fb-white);
  opacity: 0;
  transition: opacity 0.2s ease;
  white-space: nowrap;
}

/* Generic interactive hover -- nav links, CTA buttons, accordion
   triggers: a modest expand + brighter border, no label. */
.custom-cursor.is-hover .custom-cursor__ring {
  width: 42px;
  height: 42px;
  border-color: rgba(244, 242, 237, 0.75);
}

.custom-cursor.is-hover .custom-cursor__dot {
  opacity: 0;
}

/* Portfolio project cover: the ring grows into a preview-sized frame
   and carries the VIEW label; the dot hides so nothing sits under the
   label text. */
.custom-cursor.is-portfolio .custom-cursor__ring {
  width: 58px;
  height: 58px;
  border-color: rgba(244, 242, 237, 0.55);
  background: rgba(11, 8, 8, 0.35);
}

.custom-cursor.is-portfolio .custom-cursor__dot {
  opacity: 0;
}

/* External link ("OPEN") -- same modest expand as generic hover, with a
   label. */
.custom-cursor.is-external .custom-cursor__ring {
  width: 46px;
  height: 46px;
  border-color: rgba(244, 242, 237, 0.75);
}

.custom-cursor.is-external .custom-cursor__dot {
  opacity: 0;
}

.custom-cursor.is-portfolio .custom-cursor__label,
.custom-cursor.is-scan .custom-cursor__label,
.custom-cursor.is-external .custom-cursor__label {
  opacity: 1;
}

/* Scan mode already fills the ring's center with the small red point --
   the label sits just below it instead of competing for the same spot. */
.custom-cursor.is-scan .custom-cursor__label {
  position: absolute;
  top: 100%;
  margin-top: 6px;
}

/* Business Scan CTA: the ring becomes a thin scanner target -- a second,
   smaller concentric ring plus a small red center point, restrained on
   purpose (no glow/neon) per spec. */
.custom-cursor.is-scan .custom-cursor__ring {
  width: 52px;
  height: 52px;
  border-color: rgba(242, 42, 18, 0.5);
  background: rgba(11, 8, 8, 0.4);
}

.custom-cursor.is-scan .custom-cursor__ring::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--fb-red);
  box-shadow: 0 0 6px rgba(242, 42, 18, 0.7);
  transform: translate(-50%, -50%);
}

.custom-cursor.is-scan .custom-cursor__ring::after {
  content: '';
  position: absolute;
  inset: 9px;
  border: 1px solid rgba(242, 42, 18, 0.35);
  border-radius: 50%;
}

.custom-cursor.is-scan .custom-cursor__dot {
  opacity: 0;
}

/* Click pulse -- a short box-shadow ripple, deliberately not a
   transform:scale keyframe (which would fight the per-frame JS
   translate3d position update on this same element). Skipped entirely
   under reduced motion -- main.js never adds this class in that case. */
@keyframes cursorPulse {
  0% { box-shadow: 0 0 0 0 rgba(242, 42, 18, 0.35); }
  100% { box-shadow: 0 0 0 9px rgba(242, 42, 18, 0); }
}

.custom-cursor__ring.is-pulsing {
  animation: cursorPulse 0.22s var(--ease-out);
}

/* Native cursor contexts (text fields, contenteditable) -- hide the
   overlay entirely rather than layer it over the system I-beam. */
.custom-cursor.is-native {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .custom-cursor__ring.is-pulsing {
    animation: none;
  }
}

