:root {

  --light: #ffffff;
  --dark: #050505;
  --tp-blade-value-width: 70%;
  --accent: #00f0ff;
  /* Referenced by the mobile menu, the nav hover blob and the capability
     cards, but never declared — so `background: var(--lime)` on the mobile CTA
     resolved to an invalid value, fell back to transparent, and left near-black
     text on a near-black overlay. Set to the teal the hero already uses for
     .word-code so the menu matches the rest of the site.
     (Note: --accent above is a different cyan. Left alone rather than unified
     here, since other sections are built against it.) */
  --lime: #00ffcc;
}

*, *::before, *::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
  overflow: hidden; /* initial state */
  overflow-x: hidden !important; /* prevent horizontal scroll explicitly */
  background-color: var(--dark);
}

/* --- LENIS SMOOTH SCROLL --- */
html.lenis,
html.lenis body {
    height: auto;
}

.lenis.lenis-smooth {
    scroll-behavior: auto !important;
}

.lenis.lenis-smooth [data-lenis-prevent] {
    overscroll-behavior: contain;
}

.lenis.lenis-stopped {
    overflow: hidden;
}

.lenis.lenis-scrolling iframe {
    pointer-events: none;
}

/* --- HERO PIN WRAPPER --- */
.hero-pin-wrapper {
    position: relative;
    width: 100%;
    height: 100vh;
    overflow: hidden;
    /* Fences the hero's layout and paint off from the rest of the document, so
       a repaint here cannot invalidate the sections scrolling in below it. */
    contain: layout paint;
}

/* Bottom fade into the next section.
   This used to be a mask-image on .webgl. A CSS mask over a full-screen canvas
   that updates every frame forces the compositor to re-run a masked composite
   of the whole layer on every one of those frames — which is precisely the
   window where the hero is scrolling out and the budget is tightest. The next
   section is the same solid --dark, so an opaque gradient painted on top is
   pixel-identical and costs the compositor nothing. */
.hero-pin-wrapper::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 20%;
  z-index: 5;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(5, 5, 5, 0) 0%, var(--dark) 100%);
}

/* Ensure WebGL fills the wrapper, not fixed to viewport anymore */
.webgl {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: var(--dark);
}

/* --- NO-WEBGL / LOST-CONTEXT FALLBACK ---
   Set by main.js when there is no WebGL, only a software rasterizer, or the
   context is lost. The hero keeps its composition; the canvas simply stops
   being the thing that draws it. */
html.no-hero-3d .webgl {
  display: none;
}

html.no-hero-3d .hero-pin-wrapper {
  background-color: var(--dark);
  background-image: url("../images/h8.png");
  background-repeat: no-repeat;
  background-position: center right;
  background-size: cover;
}

/* --- LIGHT MOTION MODE ---
   Set by main.js on phones and low tier.

   Only `shimmer` is disabled here, and specifically because it is the one loop
   that cannot be composited: it animates background-position on an element
   using background-clip:text, so every frame is a genuine repaint of the
   gradient through the glyph mask, forever. glass-shine and cursor-blink now
   animate transform and opacity respectively, which the compositor handles
   without touching the main thread — those stay on everywhere. */
html.perf-lite .hero-name {
  animation: none;
  background-position: 0 center;
}

/* Reduced motion is a stated preference, not a performance tier: stop the
   decorative loops outright, including the blinking cursor. */
@media (prefers-reduced-motion: reduce) {
  .hero-name,
  .word-design::before,
  .word-code::after {
    animation: none;
  }
}

.tp-dfwv {
  width: calc(100vw - 16px) !important;
  max-width: 360px;
}

.tp-rotv.tp-rotv-expanded .tp-rotv_c {
  transition: height .5s ease-in-out,opacity .5s linear .5s,padding .5s ease-in-out !important;
}

.hero-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 10;
  pointer-events: none;
  font-family: 'Outfit', sans-serif;
  display: flex;
  align-items: center;
  padding: 5% 8%;
  box-sizing: border-box;
  background: linear-gradient(90deg, rgba(10, 10, 10, 0.7) 0%, rgba(10, 10, 10, 0.4) 30%, rgba(10, 10, 10, 0) 70%);
  /* backdrop-filter: blur(2px); */
}

.hero-content {
  max-width: 650px;
  pointer-events: auto;
}

.hero-title {
  font-size: clamp(2rem, 4vw, 3rem);
  font-weight: 800;
  line-height: 1.1;
  color: #fff;
  margin: 0 0 20px 0;
  text-transform: uppercase;
  perspective: 1000px;
  text-shadow: 0 4px 15px rgba(0, 0, 0, 0.8), 0 0 40px rgba(0, 0, 0, 0.3);
}

.hero-name {
  font-size: clamp(2rem, 3vw, 2.35rem);
  font-weight: 800;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  background: linear-gradient(
    135deg, 
    #ffffff 0%, 
    #f1f5f9 15%, 
    #94a3b8 35%, 
    #f1f5f9 50%, 
    #94a3b8 65%, 
    #f1f5f9 85%, 
    #ffffff 100%
  );
  background-size: 200% auto;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  display: block;
  opacity: 0;
  transform: translateY(20px);
  position: relative;
  transition: letter-spacing 0.4s cubic-bezier(0.2, 1, 0.3, 1), filter 0.4s ease;
  will-change: transform, opacity;
  cursor: default;
  margin: 0;
  filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.5));
  text-shadow: 0 0 1px rgba(255, 255, 255, 0.3);
  animation: shimmer 6s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
}

@keyframes shimmer {
  0% { background-position: -102% center; }
  100% { background-position: 102% center; }
}

.hero-name::after {
  content: "";
  position: absolute;
  bottom: -10px;
  left: 0;
  width: 40px;
  height: 2px;
  background: linear-gradient(90deg, #94a3b8, #ffffff, #94a3b8);
  opacity: 0.9;
  transition: width 0.4s ease, opacity 0.4s ease;
}

@media (hover: hover) {
  .hero-name:hover {
    filter: brightness(1.2) drop-shadow(0 0 15px rgba(255, 255, 255, 0.2));
    letter-spacing: 0.6em;
  }

  .hero-name:hover::after {
    width: 80px;
    opacity: 1;
  }
}

.hero-title .line-wrapper {
  overflow: hidden;
  display: block;
}

.hero-title .line {
  display: block;
  transform-style: preserve-3d;
  opacity: 0;
}

/* Word groups emitted by splitIntoChars(). The individual .char spans are
   inline-block, so without a nowrap box around each word a narrow line would
   break wherever it ran out of room — mid-word. */
.text-line .word,
.hero-desc .word {
  display: inline-block;
  white-space: nowrap;
}

/* Creative Typography: UI Elements in Text */
.word-design {
  display: inline-block;
  color: #ffffff;
  font-weight: 700;
  letter-spacing: 1px;
  position: relative;
  overflow: hidden;
}

.word-design::before {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 50%; height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
  /* Was animating `left`, which is a layout property — this ran a reflow of
     the title every frame, forever, for a decorative highlight. transform
     produces the identical sweep entirely on the compositor. */
  transform: translateX(-200%) skewX(-20deg);
  will-change: transform;
  animation: glass-shine 7s infinite cubic-bezier(0.2, 1, 0.3, 1);
}

@keyframes glass-shine {
  0%, 30% { transform: translateX(-200%) skewX(-20deg); }
  70%, 100% { transform: translateX(400%) skewX(-20deg); }
}

.word-code {
  display: inline-block;
  color: #00ffcc;
  font-weight: 800;
  margin: 0 6px;
  transform: translateY(-2px);
  position: relative;
  /* No overflow:hidden here: there is no shine pseudo-element to clip (that is
     .word-design), and on an inline-block it would move the baseline to the
     bottom margin edge, dropping the line once the phrase wraps to two lines. */
}

.word-code::after {
  content: '_';
  color: #00ffcc;
  animation: cursor-blink 1s infinite step-end;
}

@keyframes cursor-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

.hero-subtitle {
    opacity: 0;
    margin-top: -10px;
    margin-bottom: 20px;
}

.hero-subtitle .expertise-text {
  font-weight: 500;
}

.hero-desc {
  font-size: clamp(1rem, 1.5vw, 1.25rem);
  color: rgba(255, 255, 255, 0.95);
  line-height: 1.6;
  margin-bottom: 40px;
  max-width: 480px;
  opacity: 0;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.8);
  position: relative;
}

.hero-actions {
  display: flex;
  gap: 24px;
}

.btn {
  position: relative;
  font-family: 'Outfit', sans-serif;
  font-size: 0.95rem;
  font-weight: 700;
  padding: 18px 36px;
  border-radius: 50px;
  cursor: pointer;
  border: none;
  transition: transform 0.4s cubic-bezier(0.2, 1, 0.3, 1),
              box-shadow 0.4s cubic-bezier(0.2, 1, 0.3, 1),
              background 0.4s cubic-bezier(0.2, 1, 0.3, 1),
              border-color 0.4s cubic-bezier(0.2, 1, 0.3, 1),
              opacity 0.4s cubic-bezier(0.2, 1, 0.3, 1);
  will-change: transform, box-shadow;
  text-transform: uppercase;
  letter-spacing: 2px;
  opacity: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  overflow: hidden;
  z-index: 1;
}

.btn-primary {
  background: linear-gradient(135deg, #ffffff 0%, #f1f5f9 50%, #cbd5e1 100%);
  color: #111111;
  box-shadow: 0 10px 30px rgba(255, 255, 255, 0.15), inset 0 2px 5px rgba(255, 255, 255, 1);
}

.btn-primary:hover {
  transform: translateY(-4px) scale(1.02);
  box-shadow: 0 15px 40px rgba(255, 255, 255, 0.25), inset 0 2px 5px rgba(255, 255, 255, 1);
  background: linear-gradient(135deg, #ffffff 0%, #ffffff 50%, #e2e8f0 100%);
}

.btn-icon {
  display: flex;
  align-items: center;
  justify-content: center;
}

.btn-icon i {
  font-size: 1.1rem;
  transition: transform 0.4s cubic-bezier(0.2, 1, 0.3, 1), color 0.4s ease;
}

.btn-primary:hover .btn-icon i {
  transform: translateX(6px);
}

.btn-secondary {
  background: rgba(255, 255, 255, 0.02);
  color: #ffffff;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}

.btn-secondary::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent);
  transition: left 0.6s ease;
  z-index: -1;
}

.btn-secondary:hover {
  transform: translateY(-4px);
  border-color: rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4), inset 0 0 0 1px rgba(255, 255, 255, 0.1);
  color: #fff;
}

.btn-secondary:hover::before {
  left: 100%;
}

.btn-secondary:hover .btn-icon i {
  transform: scale(1.15) translateY(-1px);
  color: var(--light);
}

/* 5. MICRO TRUST BAR — LIQUID GLASSMORPHISM */
.trust-bar {
    display: inline-flex;
    align-items: center;
    gap: 2.2rem;
    margin-top: 36px;
    padding: 1.1rem 2.2rem;
    background: linear-gradient(180deg, rgba(20, 20, 30, 0.32), rgba(10, 10, 15, 0.52));
    backdrop-filter: blur(16px) saturate(1.5);
    -webkit-backdrop-filter: blur(16px) saturate(1.5);
    border-radius: 20px;
    border: none;
    box-shadow:
        0 20px 50px rgba(0, 0, 0, 0.5),
        inset 0 1px 1px rgba(255, 255, 255, 0.5),
        inset 0 -6px 16px rgba(255, 255, 255, 0.05),
        inset 0 0 0 1px rgba(255, 255, 255, 0.13);
    position: relative;
    overflow: hidden;
    opacity: 0;
    transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s ease;
    will-change: transform;
}

.trust-bar:hover {
    transform: translateY(-3px);
    box-shadow:
        0 28px 60px rgba(0, 0, 0, 0.65),
        0 0 30px rgba(0, 255, 204, 0.18),
        inset 0 1px 1px rgba(255, 255, 255, 0.7),
        inset 0 -6px 16px rgba(0, 255, 204, 0.06),
        inset 0 0 0 1px rgba(0, 255, 204, 0.3);
}

/* Static Specular Top Reflection */
.trust-bar::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0.02) 40%, transparent 75%);
    pointer-events: none;
    opacity: 0.8;
    transition: opacity 0.3s ease;
}

.trust-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    position: relative;
    z-index: 2;
    transition: transform 0.3s ease;
}

.trust-item:hover {
    transform: scale(1.04);
}

.trust-number {
    font-family: 'Outfit', sans-serif;
    font-size: 1.65rem;
    font-weight: 800;
    color: #ffffff;
    line-height: 1;
    letter-spacing: -0.02em;
    text-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
    display: flex;
    align-items: baseline;
    gap: 1px;
}

.trust-plus {
    color: var(--accent-cyan, #00ffcc);
    text-shadow: 0 0 12px rgba(0, 255, 204, 0.6);
    font-weight: 700;
}

.trust-label {
    font-family: 'Outfit', sans-serif;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1.8px;
    color: rgba(255, 255, 255, 0.65);
    margin-top: 5px;
}

.trust-divider {
    width: 1px;
    height: 28px;
    background: linear-gradient(to bottom, transparent, rgba(0, 255, 204, 0.35), transparent);
    position: relative;
    z-index: 2;
}

/* --- HERO: SMALL SCREENS ---------------------------------------------------
   The desktop hero is a left-anchored column sitting beside a full-bleed canvas.
   A phone has no room for that "beside", so the composition flips: a top-to-
   bottom scrim over the whole canvas, one column at full width, and every fixed
   horizontal rhythm (button row, trust bar, name tracking) relaxed so nothing is
   pushed past the viewport edge. */
@media (max-width: 768px) {
    .hero-pin-wrapper {
        height: auto;
        min-height: 100vh;
        min-height: 100svh;
        /* The wrapper can now outgrow the canvas; keep the seam invisible. */
        background-color: var(--dark);
    }

    /* The drawing buffer is sized from window.innerHeight, so letting the canvas
       box stretch to a wrapper that the copy has grown past one screen would
       squash the render vertically. Pin it to the viewport instead. */
    .webgl {
        height: 100vh;
        height: 100svh;
    }

    /* Taken out of the absolute flow so the wrapper is sized by the copy rather
       than clipping it — a phone with large text settings has to spill, not cut. */
    .hero-overlay {
        position: relative;
        height: auto;
        min-height: 100vh;
        min-height: 100svh;
        /* Was a flat 110px top pad, which pushed the whole block below centre
           and left a dead field of dots above it. The header is ~60px, so
           clearing it plus the safe-area inset is all that is needed. */
        padding:
            calc(76px + env(safe-area-inset-top, 0px))
            max(20px, env(safe-area-inset-left, 0px))
            calc(40px + env(safe-area-inset-bottom, 0px))
            max(20px, env(safe-area-inset-right, 0px));
        /* The 90deg scrim reads as a hard vertical seam at this width. */
        background: linear-gradient(180deg,
            rgba(5, 5, 5, 0.82) 0%,
            rgba(5, 5, 5, 0.55) 45%,
            rgba(5, 5, 5, 0.8) 100%);
    }

    .hero-content {
        width: 100%;
        max-width: 100%;
    }

    .hero-title {
        font-size: clamp(1.5rem, 7.4vw, 2.1rem);
        line-height: 1.08;
        margin-bottom: 14px;
    }

    .word-code {
        margin: 0;
    }

    .hero-name {
        font-size: clamp(1.05rem, 4.6vw, 1.4rem);
        letter-spacing: 0.18em;
        margin-bottom: 18px;
    }

    .hero-subtitle {
        margin-top: 0;
        margin-bottom: 14px;
    }

    .hero-desc {
        font-size: 0.95rem;
        line-height: 1.55;
        max-width: 100%;
        margin-bottom: 26px;
    }

    /* One row. The previous note here said these could never sit side by side,
       but that was true only of the old sizing: at 0.82rem with 1.5px tracking
       and 22px padding the pair needs ~395px against ~346px of usable width.
       Dropping to the clamped size below brings the pair to ~270px at a 320px
       viewport, which fits the narrowest phone still in use.

       flex: 1 1 auto (not `1 1 0`) matters: equal halves would give each 133px
       on a 320px screen, and the primary label alone needs ~152px. Growing
       from content width instead keeps the primary wider than the secondary,
       which is also the correct visual hierarchy. */
    .hero-actions {
        flex-direction: row;
        align-items: stretch;
        gap: 10px;
        /* Safety net, not the normal path: the row fits with slack at every
           width down to 320px. But a user with large-text accessibility
           settings can push the labels past the viewport, and wrapping to two
           lines is a far better failure than horizontal scroll. */
        flex-wrap: wrap;
    }

    .hero-actions > a,
    .hero-actions > .btn {
        flex: 1 1 auto;
        /* Deliberately NOT min-width: 0. The labels are nowrap, so allowing a
           flex item below its content width does not shrink the text — it just
           lets it overflow the pill. min-width: auto is the floor that keeps
           each button at least as wide as what it contains. */
    }

    .hero-actions > a {
        display: flex;
    }

    /* Only the button nested inside the anchor fills its wrapper. Applying
       width:100% to the primary as well made its flex-basis (auto -> width)
       resolve to the full row width, so both items demanded a whole line and
       wrapped. flex-shrink hid that until wrapping was enabled. */
    .hero-actions > a > .btn {
        width: 100%;
    }

    .hero-actions .btn {
        min-width: max-content;
        /* min-height, not padding alone, guarantees the 44px touch target
           once the font shrinks on narrow screens. */
        min-height: 46px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
        /* The floors here are what decide the 320px case, and that is the case
           with the least room: the clamps bottom out well before a small phone
           reaches them. Enabling flex-wrap above turned the old values from a
           silent 0.4px overflow into a visible wrap, which is how the fit was
           shown to be imaginary in the first place. */
        padding: 12px clamp(9px, 2.8vw, 15px);
        font-size: clamp(0.6rem, 2.5vw, 0.7rem);
        letter-spacing: 0.5px;
        white-space: nowrap;
    }

    /* The arrow is decoration next to a nowrap label; it must never be the
       thing that forces a wrap. */
    .hero-actions .btn-icon {
        flex: 0 0 auto;
    }
}

/* Below 360px the arrow is worth ~26px that the labels need more. */
@media (max-width: 359px) {
    .hero-actions .btn-icon {
        display: none;
    }

    .hero-actions .btn {
        gap: 0;
    }
}

@media (max-width: 768px) {
    /* inline-flex sized the bar to its content, which is wider than the screen.
       Full width with the three stats sharing it evenly instead. */
    .trust-bar {
        display: flex;
        width: 100%;
        justify-content: space-between;
        gap: 0.6rem;
        margin-top: 24px;
        padding: 0.85rem 1rem;
        border-radius: 14px;
    }

    .trust-item {
        flex: 1 1 0;
        min-width: 0;
        align-items: center;
        text-align: center;
    }

    .trust-number {
        font-size: 1.2rem;
    }

    .trust-label {
        font-size: 0.58rem;
        letter-spacing: 1px;
        margin-top: 5px;
    }

    /* Stretch, because "Client Satisfaction" wraps to two lines. */
    .trust-divider {
        height: auto;
        align-self: stretch;
    }
}

.theme-blend-zone {
    position: relative;
    z-index: 20;
    padding: 200px 0 100px 0;
    margin-top: -150px;
    background: linear-gradient(to bottom, transparent 0%, rgb(255, 255, 255) 150px, rgba(248, 250, 252, -30) 80%);
    pointer-events: none;
}


/* --- TACTILE LIQUID NAVIGATION --- */
/* --- HEADER ---
   Two states on one element. At rest it is a full-bleed bar: edge to edge,
   with a top scrim so the links stay legible over the dither without a hard
   bar edge. Past ~40px it condenses into a floating frosted pill.

   The morph is a discrete class toggle, not a scroll-scrubbed tween. width,
   top and padding are layout properties: animating them continuously against
   scroll position would relayout the header every frame. Toggled, the cost is
   paid twice — once down, once up.

   left/right + margin-inline centres the condensed pill without translateX,
   which keeps `transform` free for the hide/reveal alone. */
.engineered-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    margin-inline: auto;
    width: 100%;
    padding: 0.85rem 4vw;
    display: flex;
    justify-content: space-between;
    align-items: center;
    z-index: 100000005;
    pointer-events: none;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    transition:
        width 0.45s cubic-bezier(0.4, 0, 0.2, 1),
        top 0.45s cubic-bezier(0.4, 0, 0.2, 1),
        padding 0.45s cubic-bezier(0.4, 0, 0.2, 1),
        border-radius 0.45s cubic-bezier(0.4, 0, 0.2, 1),
        background 0.45s ease,
        border-color 0.45s ease,
        box-shadow 0.45s ease,
        transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
    will-change: transform;
}

.engineered-header:not(.is-condensed) {
    background: transparent !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    box-shadow: none !important;
    border-color: transparent !important;
}



.engineered-header.is-condensed {
    top: 6px;
    width: min(94%, 1300px);
    padding: 0.5rem 0.7rem 0.5rem 1.4rem;
    border-radius: 13px;
    /* The pill is a real surface now, so it stops letting clicks through. */
    pointer-events: auto;
    background: linear-gradient(180deg, rgba(14, 14, 22, 0.22), rgba(14, 14, 22, 0.42));
    backdrop-filter: blur(16px) saturate(1.5);
    -webkit-backdrop-filter: blur(16px) saturate(1.5);
    border-color: transparent;
    box-shadow:
        0 20px 50px rgba(0, 0, 0, 0.45),
        inset 0 1px 1px rgba(255, 255, 255, 0.5),
        inset 0 -8px 20px rgba(255, 255, 255, 0.06),
        inset 0 0 0 1px rgba(255, 255, 255, 0.13);
}

/* Scrolling down reclaims the screen; scrolling up brings it straight back.
   The extra 24px clears the pill's shadow so nothing peeks over the edge. */
.engineered-header.is-hidden {
    transform: translateY(calc(-100% - 24px));
}

@media (prefers-reduced-motion: reduce) {
    .engineered-header { transition: none; }
    /* Hiding the nav is motion the user asked not to have; the condensed
       styling is a design state and stays. */
    .engineered-header.is-hidden { transform: none; }
}

.engineered-header>* {
    pointer-events: auto;
}

.engineered-header .logo img {
    height: 50px;
}

/* 1. SKEUOMORPHIC GLASS SHELL */
/* The frosted pill now belongs to the header's condensed state, so the capsule
   is just the link row. It keeps position:relative + overflow:hidden because
   the hover blob is absolutely positioned against it and clipped by it. */
.liquid-capsule {
    position: relative;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 40px;
    padding: 0.2rem;
    box-shadow: none;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

/* 2. THE LIQUID GOOEY LAYER */
.gooey-container {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    filter: url('#liquid-goo');
    pointer-events: none;
    z-index: 1;
}

.liquid-blob {
    position: absolute;
    top: 0;
    left: 0;
    width: 0px;
    height: 100%;
    background: var(--light);
    border-radius: 50px;
    opacity: 0;
    box-shadow: 0 0 10px var(--lime);
}

/* 3. NAVIGATION TEXT */
.capsule-links {
    display: flex;
    gap: 0.5rem;
    list-style: none;
    position: relative;
    z-index: 2;
}

.cap-item {
    display: block;
    padding: 0.6rem 1.5rem;
    font-family: 'Outfit', sans-serif;
    font-size: 0.9rem;
    font-weight: 500;
    color: #fff;
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: 1px;
    border-radius: 40px;
    transition: color 0.3s ease;
    mix-blend-mode: exclusion;
}

.cap-item:hover {
    color: #000000;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 1.5rem;
}

.hamburger-btn {
    display: none;
    flex-direction: column;
    justify-content: space-between;
    width: 30px;
    height: 20px;
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 0;
    z-index: 100000002;
    pointer-events: auto;
}

.hamburger-btn span {
    width: 100%;
    height: 2px;
    background-color: #fff;
    border-radius: 2px;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    transform-origin: center;
}

.hamburger-btn.active span:nth-child(1) {
    transform: translateY(9px) rotate(45deg);
}

.hamburger-btn.active span:nth-child(2) {
    opacity: 0;
    transform: translateX(10px);
}

.hamburger-btn.active span:nth-child(3) {
    transform: translateY(-9px) rotate(-45deg);
}

/* 4. MOBILE MENU OVERLAY */
/* ============================================================================
   MOBILE MENU — rebuilt, CSS-driven
   ============================================================================
   Every part of the open/close is a CSS transition keyed off one class on the
   overlay. Nothing here is animated from JavaScript, and nothing writes inline
   styles.

   That is the point of the rewrite, not a stylistic preference. The previous
   version had GSAP tweening opacity/visibility on the same element that a
   class also set, and the two disagreed about what "closed" meant — so an
   interrupted or re-entered transition could leave the overlay painted over
   the page with its own contents faded out: a black screen. A single class
   with CSS transitions has exactly one source of truth, reverses correctly
   from any point mid-animation, and cannot be left in a partial state.
   ========================================================================= */

.mobile-menu-overlay {
    position: fixed;
    inset: 0;
    height: 100dvh;
    background: rgba(5, 5, 5, 0.97);
    backdrop-filter: blur(24px) saturate(140%);
    -webkit-backdrop-filter: blur(24px) saturate(140%);
    /* Below the header (100000005) on purpose: the hamburger lives in the
       header and has to stay clickable to close the sheet. */
    z-index: 100000001;
    display: flex;
    flex-direction: column;

    opacity: 0;
    visibility: hidden;
    /* visibility is delayed out so the fade can finish, and switched in
       instantly on open — the standard pattern for keeping a hidden overlay
       out of the accessibility tree and off the hit-test surface. */
    transition: opacity 0.32s ease, visibility 0s linear 0.32s;
}

.mobile-menu-overlay.active {
    opacity: 1;
    visibility: visible;
    transition: opacity 0.32s ease, visibility 0s linear 0s;
}

.mobile-menu-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding:
        calc(5.5rem + env(safe-area-inset-top, 0px))
        max(1.5rem, env(safe-area-inset-right, 0px))
        calc(2rem + env(safe-area-inset-bottom, 0px))
        max(1.5rem, env(safe-area-inset-left, 0px));
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}

.mobile-links {
    list-style: none;
    padding: 0;
    margin: 0 0 2.5rem;
}

.mobile-links li {
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

/* --- Staggered reveal, in CSS ---
   Per-item transition-delay replaces a JS stagger. Deterministic, and it
   unwinds correctly when the sheet is closed mid-open. */
.mob-link,
.mobile-cta-wrap,
.mobile-contact-section {
    opacity: 0;
    transform: translateX(-22px);
    transition:
        opacity 0.38s ease,
        transform 0.38s cubic-bezier(0.22, 1, 0.36, 1);
}

.mobile-cta-wrap,
.mobile-contact-section {
    transform: translateY(16px);
}

.mobile-menu-overlay.active .mob-link,
.mobile-menu-overlay.active .mobile-cta-wrap,
.mobile-menu-overlay.active .mobile-contact-section {
    opacity: 1;
    transform: none;
}

.mobile-menu-overlay.active .mobile-links li:nth-child(1) .mob-link { transition-delay: 0.10s; }
.mobile-menu-overlay.active .mobile-links li:nth-child(2) .mob-link { transition-delay: 0.15s; }
.mobile-menu-overlay.active .mobile-links li:nth-child(3) .mob-link { transition-delay: 0.20s; }
.mobile-menu-overlay.active .mobile-links li:nth-child(4) .mob-link { transition-delay: 0.25s; }
.mobile-menu-overlay.active .mobile-links li:nth-child(5) .mob-link { transition-delay: 0.30s; }
.mobile-menu-overlay.active .mobile-cta-wrap { transition-delay: 0.32s; }
.mobile-menu-overlay.active .mobile-contact-section { transition-delay: 0.38s; }

/* No delays on the way out: exits read better when they are faster and
   uniform than when they unwind item by item. */

.mob-link {
    display: block;
    padding: 1.05rem 0;
    font-family: 'Outfit', sans-serif;
    font-size: clamp(1.5rem, 7vw, 2rem);
    font-weight: 700;
    line-height: 1.2;
    color: #fff;
    text-decoration: none;
    /* Comfortably past the 44px minimum even at the smallest clamp step. */
    min-height: 56px;
}

@media (hover: hover) {
    .mob-link:hover {
        color: var(--lime);
    }
}

.mob-link:focus-visible,
.mobile-cta:focus-visible {
    outline: 2px solid var(--lime);
    outline-offset: 4px;
}

.mobile-cta-wrap {
    margin-bottom: 3rem;
}

.mobile-cta {
    width: 100%;
    max-width: 260px;
    min-height: 54px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--lime);
    color: var(--dark) !important;
    border: none;
    padding: 1rem 2.25rem;
    border-radius: 50px;
    font-family: 'Outfit', sans-serif;
    font-weight: 800;
    font-size: 1.05rem;
    letter-spacing: 0.02em;
    box-shadow: 0 10px 24px rgba(0, 255, 204, 0.18);
}

.mobile-contact-section {
    margin-top: auto;
    padding-top: 2rem;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.contact-title {
    font-family: 'Outfit', sans-serif;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--lime);
    text-transform: uppercase;
    letter-spacing: 0.24em;
    margin-bottom: 1.25rem;
}

.contact-item {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
}

.contact-icon {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--lime);
}

.contact-icon i {
    font-size: 1rem;
}

.contact-text {
    font-family: 'Outfit', sans-serif;
    font-size: 0.95rem;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.72);
}

/* A stated preference beats a flourish: show the sheet, skip the choreography. */
@media (prefers-reduced-motion: reduce) {
    .mobile-menu-overlay,
    .mob-link,
    .mobile-cta-wrap,
    .mobile-contact-section {
        transition-duration: 0.01ms !important;
        transition-delay: 0s !important;
    }
}

/* Mobile Adjustments */
@media (max-width: 768px) {
    .liquid-capsule {
        display: none;
    }

    .desktop-only {
        display: none !important;
    }

    .hamburger-btn {
        display: flex;
    }

    .engineered-header {
        padding: 0.9rem 1.4rem;
        /* Was 3px, which left a sliver of hero showing above the scrim. The
           resting bar is meant to be flush to the top edge. */
        top: 0;
    }

    /* The condensed pill hugs the edges a little tighter on a phone. */
    .engineered-header.is-condensed {
        top: 10px;
        width: calc(100% - 20px);
        padding: 0.45rem 0.6rem 0.45rem 1.1rem;
    }

    .logo {
        font-size: 1.2rem;
    }

    .engineered-header .logo img {
        height: 30px;
    }
}



/* --- MOBILE MENU: OPEN STATE ---
   The lock is a class carrying !important rather than an inline style. The old
   code set body.style.overflow on open and cleared it with '' on close, which
   also wiped the inline overflow-y:auto that unlockScroll() had written after
   the hero intro — leaving `body { overflow: hidden }` in charge and the page
   unscrollable until reload. A class cannot clobber that state because it
   never touches it. */
html.menu-open,
html.menu-open body {
    overflow: hidden !important;
}

/* While the sheet is open the header drops its condensed pill and returns to
   the flush full-width bar, so the close control sits at the screen edge
   instead of floating in a frosted capsule on top of the menu.
   html.menu-open .engineered-header outranks .engineered-header.is-condensed,
   including the copy inside the mobile media query. */
html.menu-open .engineered-header {
    top: 0;
    width: 100%;
    border-radius: 0;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-color: transparent;
    box-shadow: none;
    transform: none;
    pointer-events: auto;
}



