  /* ----- Self-hosted typography (see the preloads in <head>) -----
     Space Grotesk and JetBrains Mono are variable fonts: ONE file each covers
     the whole weight range the site uses, which is why the full type system is
     four requests. font-display: swap keeps text visible while they arrive —
     never a blank hero waiting on a font. */
  @font-face {
    font-family: 'Space Grotesk';
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url('fonts/space-grotesk-latin-var.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 300 500;
    font-display: swap;
    src: url('fonts/jetbrains-mono-latin-var.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: 'Instrument Serif';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/instrument-serif-latin-400.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: 'Instrument Serif';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/instrument-serif-latin-400-italic.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }

  /* iOS paints its own start-playback button over any video it refuses to autoplay
     (Low Power Mode, Low Data Mode, or Safari's per-site "Never Auto-Play"). It renders
     on FIRST PAINT, before any script can react — so the JS poster swap alone still
     flashes a control over the brand mark for a moment. Removing the shadow-DOM
     affordance in CSS kills it before it is ever painted. The poster attribute keeps the
     still frame visible, and the JS swap remains the belt-and-braces fallback. */
  video::-webkit-media-controls,
  video::-webkit-media-controls-enclosure,
  video::-webkit-media-controls-panel,
  video::-webkit-media-controls-overlay-play-button,
  video::-webkit-media-controls-start-playback-button {
    display: none !important;
    -webkit-appearance: none !important;
    opacity: 0 !important;
    pointer-events: none !important;
  }

  /* ============================================================
   * VEXION LABS — Gravitational Depth
   * Obsidian, void, electric blue, violet, warm gold trace.
   * ============================================================ */

  :root {
    --obsidian: #03060d;
    --void: #050912;
    --depth-1: #0a1426;
    --depth-2: #0e1a30;
    --ice: #e8eef5;
    --ice-dim: #9aa6b8;
    --ice-faint: rgba(232, 238, 245, 0.5);
    --rule: rgba(232, 238, 245, 0.08);
    --rule-bright: rgba(232, 238, 245, 0.18);

    --blue: #1e90ff;
    --blue-bright: #5cb0ff;
    --blue-deep: #1a4fff;
    --violet: #7c5cff;
    --gold: #f5b94a;

    --font-display: 'Space Grotesk', system-ui, -apple-system, sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, monospace;
    --font-serif: 'Instrument Serif', 'Times New Roman', serif;

    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
  }

  * { box-sizing: border-box; margin: 0; padding: 0; }
  html, body {
    background: var(--obsidian);
    color: var(--ice);
    font-family: var(--font-display);
    font-weight: 400;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
  }
  /* `overflow-x: hidden` on <body> turns body into a scroll container, and a
     position:sticky descendant then anchors to body's scrollport — which never
     scrolls, because the document does. Sticky silently does nothing. That is
     what killed the phone Proof stage. `clip` clips the same overflow without
     creating a scroll container; overflow-y has to stay `visible` or the used
     value of `clip` degrades straight back to `hidden`. <html> keeps `hidden`:
     the root element's overflow propagates to the viewport, so it costs
     nothing and still catches horizontal overflow. */
  body { overflow-x: clip; overflow-y: visible; }
  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; }

  body { line-height: 1.5; cursor: none; }
  @media (max-width: 900px) { body { cursor: auto; } }

  a { color: inherit; text-decoration: none; }
  img { display: block; max-width: 100%; }
  button { font: inherit; color: inherit; background: none; border: none; cursor: none; }
  ::selection { background: var(--blue); color: var(--obsidian); }

  /* ----- Background WebGL ----- */
  #bg-canvas {
    position: fixed; inset: 0;
    width: 100vw; height: 100vh;
    z-index: 0; pointer-events: none;
  }
  .bg-vignette {
    position: fixed; inset: 0; z-index: 1; pointer-events: none;
    background:
      radial-gradient(ellipse at 50% 30%, transparent 0%, rgba(3,6,13,0.4) 60%, rgba(3,6,13,0.85) 100%),
      radial-gradient(ellipse at 80% 100%, rgba(30,144,255,0.08) 0%, transparent 50%),
      radial-gradient(ellipse at 10% 0%, rgba(124,92,255,0.05) 0%, transparent 50%);
  }
  .bg-grain {
    position: fixed; inset: 0; z-index: 2; pointer-events: none;
    /* `mix-blend-mode: overlay` here was wrong on DESKTOP too, not just phones.
       A fixed full-viewport blend layer makes the compositor re-blend the entire
       screen every scrolled frame, and "desktop GPUs, that is free" is only true
       of discrete ones — on the integrated graphics in a Touch Bar MacBook Pro it
       is the single most expensive thing on the page, for a 6%-opacity noise
       texture. Plain alpha compositing of the same texture is visually
       indistinguishable and costs the compositor nothing. */
    opacity: 0.05;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='1'/></svg>");
  }
  /* Still off entirely on phones — a 6%-opacity texture is invisible on a
     6-inch screen, so even alpha compositing it is wasted work there. */
  @media (max-width: 800px) {
    .bg-grain { display: none; }
  }

  /* ----- Custom cursor ----- */
  .cursor, .cursor-ring {
    position: fixed; top: 0; left: 0; pointer-events: none;
    z-index: 9999; border-radius: 50%;
    transform: translate(-50%, -50%);
    will-change: transform;
  }
  .cursor {
    width: 6px; height: 6px;
    background: var(--blue-bright);
    box-shadow: 0 0 14px rgba(92, 176, 255, 0.8);
  }
  .cursor-ring {
    width: 36px; height: 36px;
    border: 1px solid rgba(92, 176, 255, 0.45);
    /* Deliberately width/height, NOT scale: JS rewrites `transform` every mousemove to
       track the pointer, so a transition on transform would make the ring lag behind the
       cursor. This element is position:fixed with no children, so the reflow is confined
       to itself and costs nothing measurable. */
    transition: width 0.3s var(--ease-out), height 0.3s var(--ease-out), border-color 0.3s var(--ease-out);
  }
  .cursor-ring.hover {
    width: 64px; height: 64px;
    border-color: rgba(92, 176, 255, 0.9);
    background: rgba(30, 144, 255, 0.05);
  }

  /* ----- Loader ----- */
  .loader {
    position: fixed; inset: 0; z-index: 100;
    background: var(--obsidian);
    display: flex; align-items: center; justify-content: center;
    flex-direction: column; gap: 2rem; overflow: hidden;
  }
  .loader::before {
    content: ""; position: absolute; inset: 0;
    background:
      radial-gradient(ellipse at center, rgba(30,144,255,0.10) 0%, transparent 50%),
      radial-gradient(ellipse at 30% 70%, rgba(124,92,255,0.06) 0%, transparent 60%);
    pointer-events: none;
  }
  .loader-hex {
    position: relative; width: 280px; height: 280px;
    display: flex; align-items: center; justify-content: center;
  }
  .loader-hex video {
    width: 100%; height: 100%; object-fit: contain;
    filter: drop-shadow(0 0 24px rgba(30, 144, 255, 0.35));
  }
  .loader-tag {
    position: absolute; top: 5%; left: 5vw;
    font-family: var(--font-mono);
    font-size: 11px; letter-spacing: 0.2em;
    color: var(--ice-faint); text-transform: uppercase;
  }
  .loader-tag .dot {
    display: inline-block; width: 6px; height: 6px;
    background: var(--blue-bright); border-radius: 50%;
    margin-right: 8px; animation: pulse 1.6s ease-in-out infinite;
    vertical-align: middle;
  }
  .loader-meta {
    position: absolute; inset: auto 0 8% 0;
    display: flex; justify-content: space-between;
    padding: 0 5vw; font-family: var(--font-mono);
    font-size: 11px; letter-spacing: 0.18em;
    color: var(--ice-faint); text-transform: uppercase;
  }
  .loader-meta .pct { color: var(--ice); font-variant-numeric: tabular-nums; }
  .loader-bar {
    position: absolute; bottom: 5%; left: 5vw; right: 5vw;
    height: 1px; background: var(--rule);
  }
  .loader-bar-fill {
    /* Full width, scaled from the left — the fill is driven by scaleX so the
       loader's progress write is compositor-only instead of one reflow per
       frame. */
    height: 100%; width: 100%;
    transform: scaleX(0);
    transform-origin: left center;
    background: linear-gradient(90deg, var(--blue), var(--blue-bright));
    box-shadow: 0 0 8px var(--blue-bright);
  }
  @keyframes pulse {
    0%, 100% { opacity: 0.3; }
    50% { opacity: 1; }
  }

  /* ----- HUD ----- */
  .hud {
    position: fixed; z-index: 30; pointer-events: none;
    font-family: var(--font-mono);
    font-size: 11px; letter-spacing: 0.18em;
    color: var(--ice-faint); text-transform: uppercase;
  }
  .hud-br { bottom: 5vh; right: 5vw; text-align: right; }
  /* "SCROLL" label fades out smoothly when the footer (Privacy + Terms) is in
     view — by then the visitor is at the end of the page and "scroll" is
     misleading. Section label + progress bar stay so they always know where
     they are. Toggled by IntersectionObserver in initFooterScrollLabelHide(). */
  #hud-scroll-label {
    transition: opacity 0.5s var(--ease-out),
                transform 0.5s var(--ease-out);
  }
  #hud-scroll-label.is-hidden {
    opacity: 0;
    transform: translateY(-6px);
    pointer-events: none;
  }
  .hud-section { color: var(--ice); }
  .hud-progress {
    width: 80px; height: 1px; background: var(--rule);
    position: relative; margin-top: 4px;
  }
  /* Driven by transform: scaleX(), never width. `width` is a layout property:
     writing it once per scrolled frame invalidated layout on every frame of
     every scroll, which is measurable as ~11 style recalcs per wheel click.
     A scaleX on a full-width bar is compositor-only and costs nothing. */
  .hud-progress span {
    position: absolute; left: 0; top: 0; height: 100%; width: 100%;
    transform: scaleX(0); transform-origin: 0 50%;
    background: var(--blue-bright);
    box-shadow: 0 0 6px var(--blue-bright);
  }

  /* ----- Nav ----- */
  nav.main {
    position: fixed; top: 0; left: 0; right: 0;
    z-index: 40; padding: 1.6rem 5vw;
    display: flex; align-items: center; justify-content: space-between;
  }
  /* The nav is fixed and fully transparent, so body copy and headlines scroll
     straight under the pills and read as text printed on top of buttons. A
     gradient scrim fades whatever passes behind it out before it reaches them
     — paint only, no backdrop-filter (the site's #1 mobile jank rule) and no
     scroll listener. It extends 26px past the nav's own box so the fade ends
     in empty space rather than cutting off at a hard edge. */
  nav.main::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0; bottom: -26px;
    z-index: -1;
    pointer-events: none;
    background: linear-gradient(
      180deg,
      #03060d 0%,
      rgba(3, 6, 13, 0.92) 45%,
      rgba(3, 6, 13, 0) 100%
    );
  }
  nav .logo {
    display: flex; align-items: center; gap: 0.6rem;
  }
  nav .logo img {
    height: 38px; width: auto;
    filter: drop-shadow(0 0 6px rgba(30, 144, 255, 0.3));
  }
  nav .logo .word {
    font-family: var(--font-display); font-weight: 600;
    font-size: 14px; letter-spacing: 0.18em; color: var(--ice);
  }
  nav .logo .word small {
    display: block; font-family: var(--font-mono);
    font-size: 10px; letter-spacing: 0.3em;
    color: var(--ice-faint); margin-top: 2px; font-weight: 300;
  }
  nav ul.links {
    list-style: none; display: flex; gap: 2.4rem;
    font-family: var(--font-mono); font-size: 12px;
    letter-spacing: 0.18em; text-transform: uppercase; color: var(--ice-dim);
  }
  nav ul.links a { position: relative; transition: color 0.3s var(--ease-out); }
  nav ul.links a:hover { color: var(--ice); }
  nav ul.links a::after {
    content: ""; position: absolute; left: 0; bottom: -4px;
    width: 100%; height: 1px; background: var(--blue-bright);
    transform: scaleX(0); transform-origin: left center;
    transition: transform 0.4s var(--ease-out);
  }
  nav ul.links a:hover::after { transform: scaleX(1); }
  /* Wrapper that holds the Call + Book pair on the right side of the nav. */
  .nav-actions {
    display: flex; align-items: center; gap: 0.6rem;
  }
  /* Tap-to-call pill — secondary CTA paired with Book a Call.
     Filled with a subtle blue gradient so it reads as a real button on mobile,
     and the visible phone number gives instant credibility on desktop. */
  nav .cta-call {
    display: inline-flex; align-items: center; gap: 0.5rem;
    padding: 0.55rem 1.0rem; border-radius: 999px;
    border: 1px solid rgba(92, 176, 255, 0.35);
    background: linear-gradient(180deg, rgba(30, 144, 255, 0.22), rgba(10, 20, 38, 0.72));
    font-family: var(--font-mono); font-size: 11px;
    letter-spacing: 0.14em; color: var(--ice);
    text-decoration: none;
    transition: border-color 0.3s var(--ease-out),
                background 0.3s var(--ease-out),
                transform 0.3s var(--ease-out),
                box-shadow 0.3s var(--ease-out);
  }
  nav .cta-call:hover {
    border-color: var(--blue-bright);
    background: rgba(30, 144, 255, 0.20);
    transform: translateY(-1px);
    box-shadow: 0 0 24px rgba(30, 144, 255, 0.3);
  }
  .cta-call-icon {
    color: var(--blue-bright);
    filter: drop-shadow(0 0 6px rgba(92, 176, 255, 0.55));
    flex-shrink: 0;
  }
  .cta-call-num { font-variant-numeric: tabular-nums; }
  nav .cta {
    display: inline-flex; align-items: center; gap: 0.6rem;
    padding: 0.6rem 1.2rem; border: 1px solid var(--rule-bright);
    border-radius: 999px; font-family: var(--font-mono);
    font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase;
    color: var(--ice); transition: all 0.4s var(--ease-out);
    background: linear-gradient(180deg, rgba(10, 20, 38, 0.82), rgba(6, 12, 24, 0.92));
    /* Calm by default — no pulse during the brand pitch. The pulse activates
       only when the user reaches the Booking section (.is-urgent class is
       toggled by IntersectionObserver in the booking pulse trigger below). */
  }
  nav .cta::before {
    content: ""; width: 6px; height: 6px; border-radius: 50%;
    background: var(--blue-bright); box-shadow: 0 0 8px var(--blue-bright);
  }
  nav .cta:hover {
    border-color: var(--blue-bright); background: rgba(30, 144, 255, 0.12);
    transform: translateY(-1px);
  }
  /* Urgent state — only applied when #booking is in viewport. Pulse loops
     a 2.4s halo so the visitor's eye keeps coming back to the Book a Call
     pill in case they want to scroll back up to it from the booking form. */
  nav .cta.is-urgent {
    animation: navCtaGlow 2.4s ease-in-out infinite;
  }
  @keyframes navCtaGlow {
    0%, 100% {
      border-color: var(--rule-bright);
      box-shadow:
        0 0 0 0 rgba(92,176,255,0.0),
        0 0 12px rgba(30,144,255,0.18);
    }
    50% {
      border-color: var(--blue-bright);
      box-shadow:
        0 0 0 6px rgba(92,176,255,0.10),
        0 0 28px rgba(92,176,255,0.55),
        0 0 56px rgba(30,144,255,0.30);
    }
  }
  @media (prefers-reduced-motion: reduce) {
    nav .cta.is-urgent { animation: none; }
  }
  /* ----- Mobile hamburger button -----
     Hidden on desktop (where regular nav links are visible). Switches to
     visible at ≤800px in the media query below. */
  .nav-burger {
    display: none;
    background: rgba(10, 20, 38, 0.45);
    border: 1px solid var(--rule-bright);
    border-radius: 10px;
    padding: 8px 9px;
    cursor: pointer;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 4px;
    width: 36px; height: 36px;
    transition: border-color 0.3s var(--ease-out),
                background 0.3s var(--ease-out);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  .nav-burger:hover { border-color: var(--blue-bright); background: rgba(30, 144, 255, 0.16); }
  .nav-burger-bar {
    display: block;
    width: 16px; height: 1.5px;
    background: var(--ice);
    border-radius: 2px;
    transition: transform 0.3s var(--ease-out),
                opacity 0.2s var(--ease-out);
  }
  .nav-burger.is-open .nav-burger-bar:nth-child(1) {
    transform: translateY(5.5px) rotate(45deg);
  }
  .nav-burger.is-open .nav-burger-bar:nth-child(2) { opacity: 0; }
  .nav-burger.is-open .nav-burger-bar:nth-child(3) {
    transform: translateY(-5.5px) rotate(-45deg);
  }

  /* Full-screen overlay menu shown when hamburger is tapped. */
  .mobile-menu {
    position: fixed;
    inset: 0;
    z-index: 100;
    background: linear-gradient(180deg, rgba(3, 6, 13, 0.96) 0%, rgba(8, 18, 36, 0.98) 100%);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    padding: 6vh 8vw;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.35s var(--ease-out);
  }
  .mobile-menu[hidden] { display: none; }
  .mobile-menu.is-open { opacity: 1; pointer-events: auto; }
  .mobile-menu-close {
    position: absolute;
    top: 1.4rem; right: 5vw;
    width: 38px; height: 38px;
    border: 1px solid var(--rule-bright);
    background: rgba(10, 20, 38, 0.6);
    border-radius: 10px;
    color: var(--ice);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    transition: border-color 0.3s var(--ease-out);
  }
  .mobile-menu-close:hover { border-color: var(--blue-bright); }
  .mobile-menu-nav {
    display: flex;
    flex-direction: column;
    gap: 1.4rem;
    margin-bottom: 2.4rem;
  }
  .mobile-menu-nav a {
    font-family: var(--font-display);
    font-weight: 300;
    font-size: clamp(34px, 8.5vw, 56px);
    color: var(--ice);
    text-decoration: none;
    letter-spacing: -0.02em;
    line-height: 1;
    transition: color 0.3s var(--ease-out),
                transform 0.4s var(--ease-out);
  }
  .mobile-menu-nav a:hover,
  .mobile-menu-nav a:active {
    color: var(--blue-bright);
    transform: translateX(8px);
  }
  .mobile-menu-actions {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    border-top: 1px solid var(--rule);
    padding-top: 1.8rem;
  }
  .mobile-menu-call {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    padding: 1rem 1.2rem;
    border-radius: 12px;
    border: 1px solid rgba(92, 176, 255, 0.35);
    background: rgba(30, 144, 255, 0.10);
    color: var(--ice);
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: 14px;
    letter-spacing: 0.14em;
    transition: border-color 0.3s var(--ease-out),
                background 0.3s var(--ease-out);
  }
  .mobile-menu-call:hover { border-color: var(--blue-bright); background: rgba(30, 144, 255, 0.20); }
  .mobile-menu-call svg { color: var(--blue-bright); flex-shrink: 0; filter: drop-shadow(0 0 6px rgba(92,176,255,0.55)); }
  .mobile-menu-book {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 1rem 1.2rem;
    border-radius: 12px;
    background: linear-gradient(90deg, var(--blue), var(--blue-deep));
    color: white;
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: 13px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    box-shadow: 0 6px 24px rgba(30, 144, 255, 0.4),
                inset 0 1px 0 rgba(255, 255, 255, 0.2);
    transition: transform 0.3s var(--ease-out),
                box-shadow 0.3s var(--ease-out);
  }
  .mobile-menu-book:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 36px rgba(30, 144, 255, 0.55),
                inset 0 1px 0 rgba(255, 255, 255, 0.3);
  }
  /* Body scroll lock when overlay is open. */
  body.menu-open { overflow: hidden; }

  @media (max-width: 800px) {
    nav ul.links { display: none; }
    nav .cta { padding: 0.5rem 0.9rem; font-size: 10px; }
    nav .logo .word { display: none; }
    /* On mobile the number text is hidden — only the phone icon shows so
       both CTAs fit. Still tappable, still calls the same number. */
    nav .cta-call { padding: 0.55rem 0.7rem; gap: 0; }
    nav .cta-call .cta-call-num { display: none; }
    .nav-actions { gap: 0.4rem; }
    /* Show the hamburger only on phone-sized screens. */
    .nav-burger { display: inline-flex; }
  }

  /* ----- Mobile fine-tuning (≤700px) -----
     Three issues addressed here:
     1. Logo moved UP — nav top padding cut from 1.6rem to 0.5rem and logo
        image height reduced 38px → 26px. This frees vertical space below
        the logo for the build-stage label and the page headline.
     2. Build-caption moved BELOW the now-smaller nav so it doesn't overlap
        the logo (was top: 6vh ≈ 50px, which collided with the nav bottom).
     3. Project cover cards (Lumberjays, On Demand HVAC) shrunk so
        they don't overlap the build-stage headlines on phone screens.
        220px wide on a 390px phone took up 56% of the viewport — now 130px
        (~33%) so the headline + cards both fit cleanly. */
  @media (max-width: 700px) {
    nav.main {
      padding: 0.5rem 4vw;
    }
    nav .logo img {
      height: 26px;
    }
    nav .cta {
      padding: 0.4rem 0.8rem;
      font-size: 9px;
      letter-spacing: 0.16em;
    }

    /* Project cards stacked in lower half of screen with a 14px gap.
       Bumped 115×148 → 140×180 so they have more visual presence and fit the
       hero composition cleanly. Bottom-anchored so position holds across
       different phone heights. !important is required because the base
       .sk-c1 rule later in the file has the same specificity. */
    /* Fix 5: launch card 02 (Transforming Spaces / A M Tile) was cropping the
       left edge of the website preview on phone because object-fit:cover plus
       a narrow card aspect chopped off the first letters of each line. Switch
       to contain on mobile so the whole hero shows. */
    /* Launch card 02 (A M Tile) — the screen-recorded website hero has very
       large headline text that gets clipped on phone-width cards. Scale the
       video down so all the words fit inside the frame. */
    /* Fix 3: "Custom Built To Your Standards" — shrink + tighten letter-spacing
       so the full phrase fits on phone without clipping at either edge. */
    /* Fix 4: "Built to outsell your competition" — widen the box and shrink
       the type so all five words fit on a single phone-width line. */
    /* Fix 1: home-page SCROLL cue was sitting below Safari's bottom toolbar
       on phone, so visitors never saw the prompt. Raise it well above the
       browser chrome and the bottom-right HUD. */

    /* Image area expanded to 80% on BOTH stages (Build .sk-cover-img AND
       Launch .ui-card .thumb) so the FULL website preview shows on phone —
       the whole hero from top to bottom, not cropped. Meta gets the
       remaining 20% with location hidden + tight spacing so only the
       Case label + project name show. */
    /* Tighter card chrome so meta fits the smaller 20% frame. */
  }

  /* Very small phones (iPhone SE, older Androids ~360px wide). */

  /* ----- Sections common ----- */
  main { position: relative; z-index: 5; }
  section { position: relative; padding: 0 5vw; }

  .section-tag {
    font-family: var(--font-mono); font-size: 11px;
    letter-spacing: 0.22em; color: var(--ice-faint); text-transform: uppercase;
    display: flex; align-items: center; gap: 0.8rem;
  }
  .section-tag::before {
    content: ""; width: 28px; height: 1px; background: var(--blue-bright);
  }
  @keyframes servicesTagGlow {
    0%, 100% {
      text-shadow:
        0 0 6px  rgba(92,176,255,0.35),
        0 0 18px rgba(92,176,255,0.18),
        0 0 36px rgba(30,144,255,0.10);
      color: var(--ice);
    }
    50% {
      text-shadow:
        0 0 10px rgba(92,176,255,0.85),
        0 0 28px rgba(92,176,255,0.55),
        0 0 60px rgba(30,144,255,0.40);
      color: #ffffff;
    }
  }
  .section-num {
    position: absolute; top: 6vh; right: 5vw;
    font-family: var(--font-mono); font-size: 11px;
    letter-spacing: 0.22em; color: var(--ice-faint);
    text-transform: uppercase; text-align: right; line-height: 1.6;
  }
  .section-num strong {
    display: block; font-family: var(--font-display);
    font-weight: 300; font-size: 64px; color: var(--ice);
    letter-spacing: -0.02em; line-height: 1; margin-bottom: 0.4rem;
  }
  @media (max-width: 800px) { .section-num strong { font-size: 40px; } }

  /* ----- 01 HERO ----- */
  .hero {
    min-height: 100vh; padding-top: 18vh; padding-bottom: 12vh;
    display: flex; flex-direction: column; justify-content: center;
    position: relative;
  }
  .hero h1 {
    font-family: var(--font-display); font-weight: 300;
    font-size: clamp(3rem, 11vw, 11rem); line-height: 0.95;
    letter-spacing: -0.04em; color: var(--ice); max-width: 14ch;
  }
  .hero h1 em {
    font-family: var(--font-serif); font-style: italic;
    font-weight: 400; color: var(--blue-bright);
  }
  .hero h1 .word {
    display: inline-block; overflow: hidden; vertical-align: top; margin-right: 0.18em;
  }
  .hero h1 .word > span {
    display: inline-block; will-change: transform;
  }

  /* ==========================================================
     01 — CONVERSION HERO  (added 2026-08-13)
     The first screen after the loader. Its whole job: say what we
     do, show four real builds, and put Call + Book at equal weight
     where nobody has to hunt for them. Static layout, images only —
     no WebGL, no video, no scrub — so it paints fast.
     ========================================================== */
  .hero-conv {
    position: relative;
    z-index: 7;                     /* above .anim-stage (z 5) */
    min-height: 100vh;
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: clamp(18px, 3vh, 36px);
    padding: clamp(96px, 13vh, 140px) 5vw clamp(36px, 6vh, 72px);
  }
  .hero-conv-copy { max-width: min(720px, 92vw); }
  .hero-conv h1 {
    font-family: var(--font-display);
    font-weight: 300;
    /* Sized to sit in two lines beside everything else the first screen has
       to carry (sub, CTA pair, four work tiles) inside one viewport. */
    font-size: clamp(31px, 4.3vw, 60px);
    line-height: 1.06;
    letter-spacing: -0.02em;
    color: var(--ice);
  }
  .hero-conv h1 .hero-h1-tag {
    font-weight: 400; line-height: 1.5;
    margin-bottom: clamp(18px, 3vh, 36px);   /* = .hero-conv gap */
  }
  @media (max-width: 900px) {
    .hero-conv h1 .hero-h1-tag { margin-bottom: clamp(14px, 2.2vh, 24px); }
  }
  .hero-conv h1 em {
    font-family: var(--font-serif);
    font-style: italic;
    font-weight: 400;
    color: var(--blue-bright);
  }
  .hero-conv-sub {
    max-width: 62ch;
    font-size: clamp(15px, 1.15vw, 18px);
    line-height: 1.65;
    color: var(--ice-dim);
  }
  .hero-conv-sub strong { color: var(--ice); font-weight: 500; }

  /* ----- CTA pair — Call and Book, deliberately identical in size ----- */
  .hero-cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    align-items: center;
  }
  .btn-xl {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 60px;
    padding: 0 32px;
    border-radius: 999px;
    font-family: var(--font-display);
    font-size: clamp(15px, 1.05vw, 17px);
    font-weight: 600;
    letter-spacing: 0.01em;
    text-decoration: none;
    white-space: nowrap;
    transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out);
  }
  .btn-xl:hover { transform: translateY(-2px); }
  .btn-xl-call {
    background: var(--ice);
    color: var(--obsidian);
    box-shadow: 0 10px 30px rgba(232, 238, 245, 0.14);
  }
  .btn-xl-call:hover { box-shadow: 0 16px 40px rgba(232, 238, 245, 0.22); }
  .btn-xl-book {
    background: linear-gradient(135deg, var(--blue) 0%, var(--blue-deep) 100%);
    color: #fff;
    box-shadow: 0 10px 30px rgba(30, 144, 255, 0.3);
  }
  .btn-xl-book:hover { box-shadow: 0 16px 44px rgba(30, 144, 255, 0.45); }
  /* ----- Proof strip — the three reasons to book, read in one pass ----- */
  .hero-proof {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 22px;
    margin: 0;
    padding: 0;
    list-style: none;
    font-family: var(--font-mono);
    font-size: 11.5px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ice-dim);
  }
  .hero-proof li {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  /* Separator on the gaps between items, never before the first one. */
  .hero-proof li + li::before {
    content: '';
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: var(--ice-faint);
  }
  .hero-proof-stars {
    color: var(--gold);
    letter-spacing: 0.06em;
    font-size: 12.5px;
  }

  /* ----- Three real builds, above the fold ----- */
  /* The track/stage wrappers are inert on desktop — plain blocks around the
     grid. They only earn their keep under 900px, where the strip turns into a
     scroll-driven horizontal stage (see .hero-work-track.is-pinned below). */
  .hero-work-cue, .hero-work-bar { display: none; }
  .hero-work {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: clamp(10px, 1.1vw, 18px);
  }
  .hero-work-item {
    position: relative;
    display: block;
    border: 1px solid var(--rule);
    border-radius: 12px;
    overflow: hidden;
    background: var(--depth-1);
    text-decoration: none;
    transition: transform 0.4s var(--ease-out), border-color 0.4s var(--ease-out);
  }
  .hero-work-item:hover {
    transform: translateY(-4px);
    border-color: var(--rule-bright);
  }
  /* <picture> is inline by default; a block <img> inside an inline parent
     collapses the tile's width. */
  .hero-work-item picture { display: block; }
  .hero-work-shot {
    display: block;
    width: 100%;
    /* height:auto is load-bearing — the width/height attributes on these <img>
       tags are presentational hints that otherwise beat aspect-ratio and blow
       each tile up to the asset's intrinsic height (700px). */
    height: auto;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    object-position: top center;
  }
  .hero-work-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 12px 14px 14px;
    border-top: 1px solid var(--rule);
  }
  .hero-work-name {
    font-family: var(--font-display);
    font-size: 14px;
    font-weight: 600;
    color: var(--ice);
  }
  .hero-work-kind {
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ice-faint);
  }

  @media (max-width: 900px) {
    /* Phone budget: everything above — headline, offer, both CTAs and the
       first builds — has to fit 812px of viewport, or the work drops below
       the fold and the whole point of the restructure is lost. The work
       strip becomes one horizontally-swipeable row instead of a 2×2 grid,
       which buys back ~165px. */
    .hero-conv {
      padding: clamp(78px, 10.5vh, 112px) 5vw clamp(24px, 4vh, 44px);
      gap: clamp(14px, 2.2vh, 24px);
    }
    .hero-conv-sub { font-size: 15.5px; line-height: 1.45; }
    .btn-xl { flex: 1 1 100%; min-height: 52px; }
    /* Tighter than desktop so all three sit on two lines, not three. The dot
       separators come off: the strip wraps here, and a wrapped item would
       start its line with a stray bullet. */
    .hero-proof { gap: 8px 18px; font-size: 10.5px; letter-spacing: 0.1em; }
    .hero-proof li + li::before { display: none; }

    .hero-work {
      display: flex;
      gap: 10px;
      overflow-x: auto;
      scroll-snap-type: x mandatory;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
      /* Bleed to the screen edge so the cut-off fourth tile reads as
         "there is more here", not as a broken margin. */
      margin: 0 -5vw;
      padding: 0 5vw 2px;
    }
    .hero-work::-webkit-scrollbar { display: none; }
    .hero-work-item {
      flex: 0 0 62%;
      scroll-snap-align: start;
    }
    .hero-work-meta { padding: 9px 10px 11px; }
    .hero-work-name { font-size: 12.5px; }

    /* Cue line above the strip. Without it the cut-off tile is the only hint
       that three more builds exist, and on a phone that hint gets missed. */
    .hero-work-cue {
      display: flex;
      align-items: baseline;
      gap: 10px;
      font-family: var(--font-mono);
      font-size: 10.5px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--ice-faint);
    }
    .hero-work-cue-label { margin-right: auto; }
    .hero-work-cue-count { color: var(--ice); }
    .hero-work-cue-count b { color: var(--blue-bright); font-weight: 500; }
    /* Only one of the two right-hand cues shows: the live counter once the
       scrub owns the strip, the swipe hint when it does not (reduced motion,
       or JS never booted and the strip is still a native swipe rail). */
    .hero-work-cue-count { display: none; }
    .hero-work-track.is-pinned .hero-work-cue-count { display: inline; }
    .hero-work-track.is-pinned .hero-work-cue-swipe { display: none; }

    /* ----- Scroll-driven horizontal stage (JS adds .is-pinned) -----
       A sticky stage, not a ScrollTrigger pin: a pin spacer gets invalidated
       every time iOS shows or hides its address bar, and sticky is already how
       the phone Proof stage holds still (see buildStickyStage). The track's
       height is set in JS from the real rail width, so the scrub distance and
       the scroll distance are the same number by construction.
       Everything moves on transform only — one x tween on the rail, one
       scaleX on the progress bar. No layout reads while scrolling. */
    .hero-work-track.is-pinned {
      position: relative;
      margin: 0 -5vw;
    }
    .hero-work-track.is-pinned .hero-work-stage {
      position: sticky;
      top: 0;
      height: 100svh;
      display: flex;
      flex-direction: column;
      justify-content: center;
      gap: 14px;
      overflow: hidden;
      /* clears the sticky Call / Book bar */
      padding: 0 5vw 78px;
    }
    /* The stage's empty bands now overlap the hero above and the next section
       below (negative margins in initHeroWorkPin) — they must never eat a tap. */
    .hero-work-track.is-pinned .hero-work-stage { pointer-events: none; }
    .hero-work-track.is-pinned .hero-work-item { pointer-events: auto; }
    .hero-work-track.is-pinned .hero-work {
      overflow: visible;
      scroll-snap-type: none;
      margin: 0;
      padding: 0;
      will-change: transform;
    }
    .hero-work-track.is-pinned .hero-work-item {
      flex: 0 0 80vw;
      scroll-snap-align: none;
    }
    /* Taller crop only while the strip owns the whole screen: a 16/10 tile is
       ~220px inside an 812px stage and leaves the phone looking half empty.
       Portrait also shows more of each build — these are tall pages. */
    .hero-work-track.is-pinned .hero-work-shot { aspect-ratio: 3 / 4; }
    .hero-work-bar {
      display: block;
      height: 2px;
      background: var(--rule);
      border-radius: 2px;
      overflow: hidden;
    }
    .hero-work-bar i {
      display: block;
      height: 100%;
      background: var(--blue-bright);
      transform: scaleX(0);
      transform-origin: left center;
    }
  }

  /* ==========================================================
     STICKY CALL / BOOK BAR  (added 2026-08-13)
     Appears once the hero scrolls away so the two actions are
     never more than a thumb away. Solid background — no
     backdrop-filter, which is the site's #1 mobile jank rule.
     ========================================================== */
  .sticky-cta {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 45;
    display: flex;
    gap: 10px;
    justify-content: center;
    padding: 10px 12px;
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    background: rgba(3, 6, 13, 0.94);
    border-top: 1px solid var(--rule);
    transform: translateY(115%);
    transition: transform 0.4s var(--ease-out);
    pointer-events: none;
    will-change: transform;
  }
  .sticky-cta.is-visible { transform: translateY(0); pointer-events: auto; }
  .sticky-cta a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    flex: 1 1 0;
    max-width: 280px;
    min-height: 50px;
    border-radius: 999px;
    font-family: var(--font-display);
    font-size: 15px;
    font-weight: 600;
    text-decoration: none;
  }
  .sticky-cta-call { background: var(--ice); color: var(--obsidian); }
  .sticky-cta-book { background: linear-gradient(135deg, var(--blue) 0%, var(--blue-deep) 100%); color: #fff; }
  /* Keep the footer's last line clear of the bar. */
  .site-footer { padding-bottom: 96px; }
  @media (prefers-reduced-motion: reduce) {
    .sticky-cta { transition: none; }
  }

  /* ----- BUILD SEQUENCE -----
     Three discrete scroll-anchor sections (.scene) drive a single fixed
     animation stage (.anim-stage). Each scene = ~1 viewport of scroll =
     one "page" of the build experience. Stage covers the viewport during
     the assembly, fades out before ABOUT enters.
  */
  .build {
    position: relative; padding: 0;
  }
  .anim-stage {
    position: fixed;
    inset: 0;
    z-index: 5;
    overflow: hidden;
    perspective: 1400px;
    perspective-origin: 50% 45%;
    pointer-events: none;
    /* 2026-08-13: the assembly no longer opens the page — it now sits between
       PROCESS and the CTA banner. The stage is position:fixed, so it must
       start invisible or it would cover the new conversion hero. JS fades it
       in as #scene-origin arrives and out again at the CTA banner. */
    opacity: 0;
    will-change: opacity;
    transition: none;
  }
  .scene {
    position: relative;
    height: 100vh;
    height: 100svh;
    width: 100%;
    z-index: 6;          /* above .anim-stage (z 5) so markers show through */
    pointer-events: none;
    overflow: hidden;
  }
  /* Phones drop the assembly (2026-08-14): three viewport-tall anchors carrying
     11 words sat between PROCESS and BOOKING. 800px matches the MOBILE latch in
     app.js, which skips buildSequence() at the same width. */
  @media (max-width: 800px) {
    .scene, .anim-stage { display: none; }
  }
  /* Legacy class kept for backward compat — repointed to anim-stage props */
  /* Act intro overlays — three of them, one per act */

  /* Act 1 — origin dot + hex blueprint */

  /* Act 3 — launch burst + final logo emergence */
  /* Wireframe skeleton shapes (Stage 02) */
  @keyframes shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
  }

  /* Skeleton text — animates in during Assemble */

  /* Animated text videos (mp4 loops generated externally) */
  /* Container tweaks so the videos sit right inside the existing pill/bar shapes */

  /* Hero block — strip the skeleton frame, deep navy bg, video text on top */

  /* Top bar — keep the pill shape but kill the dashed skeleton + shimmer */

  /* Hide the two stray skeleton lines under the headline */

  /* ----- Native animated text for the build-stage skeletons ----- */

  /* Top pill: "Custom Built To Your Standards" — bumped up + 4s glow pulse
     so it reads as a tagline rather than a label, and catches the eye. */

  /* Hero block: "Built to outsell your competition" — text only, no skel box.
     The .ui-skel base normally adds a gradient bg + dashed border + shimmer;
     we suppress all of that here so the headline blends into the page bg. */

  /* Letter-cascade: each letter eases in with stagger + blur clear */

  /* Word-stagger: bigger reveal — each word floats up with blur clear */

  /* Cover cards (right column) — actual project previews instead of skeletons */
  /* Real project cards (post-fly-in) get the same glow for continuity. */
  /* 3 shadow layers instead of 5 — cuts paint cost ~40% on phones while
     keeping the visual punch. The 120px far-glow was rarely visible against
     dark backgrounds; trimming it removes the most expensive blur radius. */
  /* Case 01 (Lumberjays) only — its cover art is wider than the 60%-height
     frame, so `cover` sliced the leading letters off "TREE TO DROP / SNOW TO
     PLOW". `contain` letterboxes it against the frame's own #050505 so the
     full headline reads. Same treatment the <=430px overrides already apply
     to both covers; Case 02 (HVAC) is deliberately left on `cover`. */
  /* CTA pill skeleton — solid blue look so the text reads */

  /* Spotlight sweep (Stage 04) */
  /* Build-caption (top-left BUILD / Alive / Launch label) hidden — the
     bottom-right HUD already shows the same stage info, so this top-left
     duplicate was visual clutter. Kept the rules in the file in case you
     ever want to bring it back. */
  /* scaleX, not width — see .hud-progress span above. */

  /* Browser frame */
  .browser {
    position: relative;
    width: min(78vw, 1200px);
    height: min(64vh, 720px);
    background: linear-gradient(180deg, #0a1426 0%, #050912 100%);
    border: 1px solid var(--rule-bright);
    border-radius: 14px;
    box-shadow:
      0 30px 80px rgba(0, 0, 0, 0.6),
      0 0 60px rgba(30, 144, 255, 0.08),
      inset 0 1px 0 rgba(255,255,255,0.04);
    overflow: hidden;
    transform-style: preserve-3d;
  }

  /* Pre-JS preflight: keep build-sequence elements invisible until
     gsap.set() in buildSequence() takes over. Without this, refreshes
     flash the fully assembled state for one frame between loader fade
     and timeline init. .js-ready is added in boot before buildSequence. */
  html:not(.js-ready) .browser { opacity: 0 !important; visibility: hidden; }

  .ui-hero { top: 90px; left: 32px; width: 56%; }
  .ui-hero h2 {
    font-family: var(--font-display); font-weight: 300;
    /* Bumped from clamp(36, 5.4vw, 80) → clamp(48, 6.8vw, 104) so the headline
       reads at a glance even from across a desk. */
    font-size: clamp(48px, 6.8vw, 104px); line-height: 1.02;
    letter-spacing: -0.02em; color: var(--ice);
    word-spacing: 0.12em; white-space: nowrap;
  }
  /* Phone override: "Beyond the surface" was overflowing on small viewports
     because the parent .ui-hero is only 56% wide and the desktop font min
     was 48px — too big to fit on a 220px column. Expand the container on
     phone, drop the font min, and allow wrapping if absolutely needed. */
  @media (max-width: 700px) {
    .ui-hero { width: 60vw !important; left: 4vw !important; }
    .ui-hero h2 {
      font-size: clamp(28px, 7vw, 36px) !important;
      white-space: normal !important;
      line-height: 1.05;
    }
    .ui-hero p {
      font-size: 12px !important;
      line-height: 1.45 !important;
      max-width: none !important;
    }
  }
  .ui-hero h2 .word {
    display: inline-block;
    /* No more cycling — the word is visible whenever the parent .ui-hero
       piece is visible. The previous heroWord 9s infinite animation hid
       each word for ~25% of every cycle, so scrolling in at the wrong
       phase showed a blank or fading line. */
    opacity: 1; transform: none;
  }
  .ui-hero h2 em {
    font-family: var(--font-serif); font-style: italic; color: var(--blue-bright);
    /* Stable bright glow instead of pulsing in and out. */
    text-shadow: 0 0 22px rgba(30,144,255,0.55), 0 0 44px rgba(30,144,255,0.25);
  }
  .ui-hero p {
    margin-top: 26px; color: var(--ice); max-width: 52ch;
    /* Bumped from clamp(15, 1.15vw, 18) → clamp(18, 1.45vw, 24) so the body
       copy is legible without leaning in. Color punched up ice-dim → ice. */
    font-size: clamp(18px, 1.45vw, 24px); line-height: 1.55;
    text-shadow: 0 0 16px rgba(0,0,0,0.6);
  }
  .ui-hero p .line {
    display: block;
    /* Stop hiding lines on a 9s loop — they stay readable as long as the
       parent piece is on screen. */
    opacity: 1; transform: none;
  }
  @keyframes marquee { to { transform: translateX(-50%); } }

  /* Deploy log — sits just above the marquee, centered */

  /* ----- Display type ----- */
  .display {
    font-family: var(--font-display); font-weight: 300;
    font-size: clamp(2.5rem, 7vw, 7rem); line-height: 1;
    letter-spacing: -0.03em; color: var(--ice);
  }
  .display em {
    font-family: var(--font-serif); font-style: italic; color: var(--blue-bright);
  }
  .display .stroke {
    color: transparent;
    -webkit-text-stroke: 1px rgba(232,238,245,0.3);
  }

  /* ===== Glowing pulse headlines =====
     Each major headline gets a blurred CLONE of itself layered behind the
     real text (built by initGlowHeaders() in JS). Only the clone's opacity
     animates — the blur itself is static — so the pulse runs entirely on
     the GPU compositor and adds zero cost to scrolling. The real text stays
     crisp on top. */
  /* Doubled class so the clone's `position: absolute` outranks headline rules
     declared later (e.g. `.hero-headline { position: relative }`) — otherwise
     the clone falls back into flow and shows as blurred ghost text. */
  .glow-clone.glow-clone {
    position: absolute;
    inset: 0;
    margin: 0 !important;
    z-index: -1;
    pointer-events: none;
    user-select: none;
    filter: blur(18px);
    opacity: 0.5;
    animation: headlineGlow 6s ease-in-out infinite;
    will-change: opacity;
  }
  @keyframes headlineGlow {
    0%, 100% { opacity: 0.35; }
    50%      { opacity: 0.75; }
  }
  /* Phones and weak GPUs (.vx-lite, tier 1+): hold a static glow — a pulsing
     blurred layer re-runs the blur on the GPU every frame.
     Reduced motion: same — glow yes, pulse no.
     Doubled class to outrank .glow-clone.glow-clone above. */
  .vx-lite .glow-clone.glow-clone { animation: none; opacity: 0.45; will-change: auto; }
  @media (max-width: 800px) {
    .glow-clone.glow-clone { animation: none; opacity: 0.45; filter: blur(14px); will-change: auto; }
  }
  @media (prefers-reduced-motion: reduce) {
    .glow-clone.glow-clone { animation: none; opacity: 0.4; will-change: auto; }
  }

  /* ----- 02 ABOUT ----- */
  .about { padding-top: 24vh; padding-bottom: 18vh; position: relative; }
  .about-grid {
    display: grid; grid-template-columns: 1fr 1.4fr;
    gap: 6vw; align-items: start; margin-top: 4rem;
  }
  @media (max-width: 900px) { .about-grid { grid-template-columns: 1fr; gap: 3rem; } }
  .about-grid aside {
    font-family: var(--font-mono); font-size: 12px;
    letter-spacing: 0.18em; color: var(--ice-faint); text-transform: uppercase;
    line-height: 1.8; border-top: 1px solid var(--rule); padding-top: 1.5rem;
  }
  .about-grid aside strong {
    color: var(--ice); font-family: var(--font-display); font-weight: 400;
    text-transform: none; font-size: 14px; letter-spacing: 0;
    display: block; margin-top: 0.4rem; margin-bottom: 1rem;
  }
  .about-body p {
    font-size: clamp(1.2rem, 1.9vw, 1.7rem); line-height: 1.4;
    color: var(--ice-dim); margin-bottom: 1.8rem; max-width: 38ch;
  }
  .about-body p .accent { color: var(--ice); }
  .about-body p em {
    font-family: var(--font-serif); color: var(--blue-bright); font-style: italic;
  }

  /* ----- 02 ABOUT — Conversion hero override ----- */
  .about-hero {
    min-height: 100vh;
    padding-top: 14vh; padding-bottom: 14vh;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    text-align: center;
    position: relative; overflow: hidden;
  }
  .about-hero .section-num,
  .about-hero .section-tag { opacity: 0.7; }

  /* Animated background */
  /* 3D Three.js scene — fixed to the viewport so the globe stays visually
     locked in frame the entire time the About section is on screen, instead
     of scrolling out of view with the section content. IntersectionObserver
     fades it in when About enters and out when it leaves so it never competes
     with other sections. z-index sits above the body bg-canvas (z:0) but
     below all section content (z:2+). */
  /* When the 3D canvas is ready, fade out the SVG fallback so they don't stack. */

  /* Headline */
  .hero-headline {
    position: relative; z-index: 2;
    font-family: var(--font-display); font-weight: 300;
    font-size: clamp(36px, 6vw, 96px);
    line-height: 0.98; letter-spacing: -0.03em;
    color: var(--ice);
    display: flex; flex-direction: column; gap: 0.04em;
    margin: 0;
    max-width: 18ch;
  }
  .hero-headline .line { display: block; }
  .hero-headline em {
    font-family: var(--font-display);
    font-style: normal;
    background: linear-gradient(180deg, #5cb0ff 0%, #1e90ff 60%, #7c5cff 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }

  /* "Who we are / How we work / Why it matters" 3-column About block */
  .about-deeper {
    position: relative; z-index: 2;
    margin: 4rem auto 0;
    max-width: 1100px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    text-align: left;
    padding: 0 2vw;
  }
  @media (max-width: 900px) {
    .about-deeper { grid-template-columns: 1fr; gap: 1.6rem; max-width: 60ch; }
  }
  .about-deeper-block {
    /* Pushed even further see-through (0.22 → 0.10) so the galaxy is the
       dominant visual through the cards. Lighter backdrop-blur (10 → 6) so
       the galaxy isn't muddied by the frosted plate. Border stays visible to
       hold the card boundary cleanly. */
    background: rgba(10, 20, 38, 0.65);
    border: 1px solid rgba(92, 176, 255, 0.28);
    border-radius: 14px;
    padding: 1.6rem 1.6rem 1.8rem;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
    transition: border-color 0.4s var(--ease-out),
                box-shadow 0.4s var(--ease-out),
                transform 0.4s var(--ease-out),
                background 0.4s var(--ease-out);
  }
  .about-deeper-block:hover {
    background: rgba(10, 20, 38, 0.20);
    border-color: rgba(92, 176, 255, 0.55);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.22),
                0 0 32px rgba(30, 144, 255, 0.22);
    transform: translateY(-3px);
  }
  .about-deeper-label {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--blue-bright);
    margin-bottom: 0.9rem;
    padding-bottom: 0.7rem;
    border-bottom: 1px solid rgba(92, 176, 255, 0.22);
    text-shadow: 0 0 12px rgba(92, 176, 255, 0.5);
  }
  .about-deeper-block p {
    /* Text now more transparent (0.92 → 0.78) so the galaxy bleeds visibly
       through the words. Stronger black text-shadow keeps it readable
       against any galaxy color phase (violet / cyan / blue). */
    color: rgba(232, 238, 245, 0.78);
    font-size: 15.5px;
    line-height: 1.65;
    margin: 0;
    text-shadow: 0 1px 12px rgba(0, 0, 0, 0.7),
                 0 0 4px rgba(0, 0, 0, 0.5);
  }

  /* Floating cards */
  .hero-card {
    position: absolute; z-index: 3;
    background: rgba(10,20,38,0.55);
    border: 1px solid rgba(92,176,255,0.18);
    border-radius: 14px;
    padding: 14px 16px;
    box-shadow: 0 30px 80px -30px rgba(0,0,0,0.6),
                0 0 60px -20px rgba(30,144,255,0.15);
    color: var(--ice);
    font-family: var(--font-body);
  }
  .hero-card-right { right: 3vw; top: 50%; transform: translateY(-50%); width: 200px; text-align: left; }

  .hcr-head, .hcr-foot {
    display: flex; align-items: center; gap: 7px;
    font-family: var(--font-mono); font-size: 9px;
    letter-spacing: 0.22em; text-transform: uppercase;
    color: var(--ice-faint);
  }
  .hcr-foot { margin-top: 10px; color: var(--blue-bright); }
  .hcr-dot {
    width: 5px; height: 5px; border-radius: 50%;
    background: #2ecc71;
    box-shadow: 0 0 8px #2ecc71;
    animation: hcrPulse 2s ease-in-out infinite;
  }
  @keyframes hcrPulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.5; }
  }
  .hcr-list {
    list-style: none; padding: 0; margin: 10px 0 0;
    display: flex; flex-direction: column; gap: 7px;
  }
  .hcr-list li {
    display: flex; align-items: center; gap: 8px;
    font-size: 12px; color: var(--ice);
  }
  .hcr-bullet {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--blue-bright);
    box-shadow: 0 0 8px rgba(30,144,255,0.6);
  }
  .hcr-bullet.b2 { background: #7c5cff; box-shadow: 0 0 8px rgba(124,92,255,0.6); }
  .hcr-bullet.b3 { background: #5cb0ff; box-shadow: 0 0 8px rgba(92,176,255,0.6); }
  .hcr-bullet.b4 { background: #7c5cff; box-shadow: 0 0 8px rgba(124,92,255,0.6); }
  .hcr-bullet.b5 { background: var(--blue-bright); box-shadow: 0 0 8px rgba(30,144,255,0.6); }

  @media (max-width: 1100px) {
    .hero-card-right { position: relative; right: auto; top: auto; transform: none; margin: 24px auto 0; }
  }

  /* ----- About / Studio: phone tightening -----
     The section had 14vh top/bottom padding which on a 750px-tall iPhone
     screen ate ~210px of empty space before the headline. Combined with the
     huge headline + 3 deeper blocks + 2 floating cards, the section was
     hard to scan. Tightening for ≤700px:
     - Cuts vertical padding so the headline reaches the eye sooner
     - Smaller deeper-block padding so 3 cards fit in less scroll
     - More breathing room between deeper grid and the floating cards below */
  @media (max-width: 700px) {
    .about-hero {
      padding-top: 9vh;
      padding-bottom: 9vh;
    }
    .hero-headline {
      font-size: clamp(30px, 7.5vw, 48px);
      max-width: none;
    }
    .about-deeper {
      margin: 2.8rem auto 0;
      gap: 1rem;
      padding: 0;
    }
    .about-deeper-block {
      padding: 1.3rem 1.3rem 1.5rem;
    }
    .about-deeper-label {
      font-size: 10px;
      margin-bottom: 0.7rem;
      padding-bottom: 0.5rem;
    }
    .about-deeper-block p {
      font-size: 14.5px;
      line-height: 1.6;
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .hcr-dot {
      animation: none;
    }
  }

  /* ----- 03 SERVICES ----- */
  /* ----- 05 SELECTED WORK ----- */
  .work { padding-top: 18vh; padding-bottom: 18vh; position: relative; }
  .work-card {
    border: 1px solid var(--rule); border-radius: 14px; overflow: hidden;
    background: linear-gradient(180deg, var(--depth-1), var(--void));
    transition: border-color 0.4s var(--ease-out), transform 0.4s var(--ease-out);
  }
  .work-card:hover { border-color: var(--rule-bright); transform: translateY(-4px); }
  /* Padding-ratio box (16:10) instead of aspect-ratio — the latter collapsed to
     1px in some mobile rendering contexts. This is bulletproof cross-browser. */
  .work-meta {
    display: flex; align-items: center; gap: 0.8rem;
    font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.16em;
    text-transform: uppercase; color: var(--ice-faint); margin-bottom: 1rem;
  }
  .work-card h3 {
    font-family: var(--font-display); font-weight: 400;
    font-size: clamp(1.6rem, 2.6vw, 2.2rem); color: var(--ice);
    line-height: 1; margin-bottom: 0.4rem;
  }

  /* ----- 04 PROCESS ----- */
  .process { padding-top: 18vh; padding-bottom: 18vh; position: relative; }
  .process-stages {
    margin-top: 6rem; display: grid;
    grid-template-columns: repeat(4, 1fr); gap: 2rem;
  }
  @media (max-width: 900px) { .process-stages { grid-template-columns: 1fr 1fr; } }
  @media (max-width: 600px) { .process-stages { grid-template-columns: 1fr; } }
  .stage {
    border-top: 1px solid var(--rule);
    padding-top: 1.6rem; position: relative;
  }
  .stage::before {
    content: ""; position: absolute; top: -1px; left: 0;
    width: 30%; height: 1px; background: var(--blue-bright);
    box-shadow: 0 0 6px var(--blue-bright);
  }
  .stage .step {
    font-family: var(--font-mono); font-size: 10px;
    letter-spacing: 0.22em; color: var(--ice-faint);
    text-transform: uppercase; margin-bottom: 1rem;
  }
  .stage h3 {
    font-family: var(--font-display); font-weight: 300;
    font-size: clamp(1.4rem, 2.4vw, 2rem);
    color: var(--ice); letter-spacing: -0.02em;
    line-height: 1.05; margin-bottom: 1rem;
  }
  .stage h3 em {
    font-family: var(--font-serif); color: var(--blue-bright); font-style: italic;
  }
  .stage p { color: var(--ice-dim); font-size: 13px; line-height: 1.6; }

  /* Process stepper (2026-10-12): big outlined step number per stage plus a
     progress rail that fills as you scroll. Rail = horizontal across the top
     of the grid on wide screens, vertical down the left on phones. Fill is a
     scaleX/scaleY transform only. Without JS (or reduced motion) the rail
     shows full and everything is visible. */
  .process-stages { position: relative; }
  .process-rail {
    position: absolute; left: 0; right: 0; top: 0; height: 1px;
    background: var(--rule); pointer-events: none;
  }
  .process-rail-fill {
    position: absolute; inset: 0; background: var(--blue-bright);
    box-shadow: 0 0 8px var(--blue-bright);
    transform-origin: left center;
  }
  .stage-num {
    font-family: var(--font-display); font-weight: 300;
    font-size: clamp(3.6rem, 6vw, 5.5rem); line-height: 0.9;
    letter-spacing: -0.04em; margin-bottom: 0.9rem;
    color: transparent; -webkit-text-stroke: 1px var(--blue-bright);
  }
  .stage::after {
    content: ""; position: absolute; top: -4px; left: 0;
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--blue-bright); box-shadow: 0 0 10px var(--blue-bright);
  }
  @media (max-width: 900px) and (min-width: 601px) {
    .process-rail { display: none; }
  }
  @media (max-width: 600px) {
    /* 18vh bottom + About's top padding left ~280px of empty space on phones */
    .process { padding-bottom: 6vh; }
    .process-stages { margin-top: 3.5rem; gap: 2.6rem; padding-left: 1.6rem; }
    .process-rail { left: 3px; right: auto; top: 0; bottom: 0; width: 1px; height: auto; }
    .process-rail-fill { transform-origin: center top; }
    .stage { border-top: 0; padding-top: 0; }
    .stage::before { display: none; }
    .stage::after { top: 0.4rem; left: calc(-1.6rem); }
    .stage-num { font-size: 4.2rem; }
  }

  /* ----- 03/04 — Larger type + 4s glow pulse to draw the eye ----- */
  /* Process section: same enlarged + glow tag as Services. */
  #process .section-tag {
    font-size: 20px;
    letter-spacing: 0.32em;
    color: var(--ice);
    gap: 1.1rem;
  }
  #process .section-tag::before {
    width: 44px;
    background: var(--blue-bright);
    box-shadow: 0 0 10px var(--blue-bright);
  }
  #process .section-tag span {
    animation: servicesTagGlow 4s ease-in-out infinite;
  }

  /* Bigger display headline and stage titles for this section. */
  #process .display {
    font-size: clamp(3rem, 8vw, 8.5rem);
  }
  #process .stage h3 {
    font-size: clamp(1.6rem, 2.8vw, 2.4rem);
  }
  #process .stage p {
    font-size: 15px; line-height: 1.7;
  }
  #process .stage .step {
    font-size: 12px;
  }

  /* 4s glow pulse on the eye-catching elements (display headlines, row/stage titles).
     Em accents pulse a little brighter since they're the colored highlight word. */
  #process .display,
  #work .display,
  #process .stage h3 {
    animation: textGlowPulse 4s ease-in-out infinite;
  }
  #process .display em,
  #work .display em,
  #process .stage h3 em {
    animation: textGlowPulseAccent 4s ease-in-out infinite;
  }

  /* Subtle static glow on body copy and small labels — readability over spectacle. */
  #process .stage p,
  #process .stage .step {
    text-shadow:
      0 0 8px rgba(92,176,255,0.18),
      0 0 18px rgba(30,144,255,0.10);
  }

  @keyframes textGlowPulse {
    0%, 100% {
      text-shadow:
        0 0 6px  rgba(92,176,255,0.30),
        0 0 18px rgba(92,176,255,0.15),
        0 0 36px rgba(30,144,255,0.08);
    }
    50% {
      text-shadow:
        0 0 10px rgba(92,176,255,0.75),
        0 0 28px rgba(92,176,255,0.45),
        0 0 60px rgba(30,144,255,0.30);
    }
  }
  @keyframes textGlowPulseAccent {
    0%, 100% {
      text-shadow:
        0 0 8px  rgba(124,92,255,0.40),
        0 0 22px rgba(92,176,255,0.25),
        0 0 44px rgba(30,144,255,0.12);
    }
    50% {
      text-shadow:
        0 0 14px rgba(124,92,255,0.95),
        0 0 36px rgba(92,176,255,0.65),
        0 0 72px rgba(30,144,255,0.40);
    }
  }
  @media (prefers-reduced-motion: reduce) {
    #process .section-tag span,
    #process .display, #process .stage h3,
    #process .display em, #process .stage h3 em {
      animation: none;
    }
  }

  /* ----- 05 BOOKING — the LOUDEST section. -----
     This is the conversion target. Type is bumped beyond Services/Process,
     the tag pulses faster, the headline glows brighter, and the em accent
     uses an amplified color cycle so it's the most attention-grabbing
     headline on the entire page. */
  #booking .section-tag {
    font-size: 22px;                    /* +2 over services/process (20px) */
    letter-spacing: 0.34em;              /* +0.02 wider for presence */
    color: var(--ice);
    gap: 1.2rem;
  }
  #booking .section-tag::before {
    width: 52px;                         /* +8 over services/process (44px) */
    background: var(--blue-bright);
    box-shadow: 0 0 14px var(--blue-bright);
  }
  #booking .section-tag span {
    /* 3.2s pulse — slightly faster than 4s on services/process so it reads
       as more urgent. */
    animation: bookingTagGlow 3.2s ease-in-out infinite;
  }
  @keyframes bookingTagGlow {
    0%, 100% {
      text-shadow:
        0 0 8px  rgba(92,176,255,0.40),
        0 0 22px rgba(92,176,255,0.20),
        0 0 44px rgba(30,144,255,0.12);
      color: var(--ice);
    }
    50% {
      text-shadow:
        0 0 14px rgba(92,176,255,1.00),
        0 0 36px rgba(92,176,255,0.75),
        0 0 76px rgba(30,144,255,0.50);
      color: #ffffff;
    }
  }

  /* Display headline: bigger than services/process (which is clamp(3, 8vw, 8.5)).
     Booking headline can fill a whole hero. */
  #booking .display {
    font-size: clamp(3.4rem, 9vw, 10rem);
    line-height: 0.98;
    letter-spacing: -0.035em;
    animation: bookingDisplayGlow 3.2s ease-in-out infinite;
  }
  #booking .display em {
    /* Accent word ("1–3 days") gets the loudest treatment on the whole page. */
    animation: bookingAccentGlow 3.2s ease-in-out infinite;
  }
  @keyframes bookingDisplayGlow {
    0%, 100% {
      text-shadow:
        0 0 8px  rgba(92,176,255,0.35),
        0 0 22px rgba(92,176,255,0.18),
        0 0 44px rgba(30,144,255,0.10);
    }
    50% {
      text-shadow:
        0 0 14px rgba(92,176,255,0.95),
        0 0 36px rgba(92,176,255,0.60),
        0 0 76px rgba(30,144,255,0.40);
    }
  }
  @keyframes bookingAccentGlow {
    0%, 100% {
      text-shadow:
        0 0 10px rgba(124,92,255,0.55),
        0 0 28px rgba(92,176,255,0.30),
        0 0 56px rgba(30,144,255,0.18);
    }
    50% {
      text-shadow:
        0 0 18px rgba(124,92,255,1.00),
        0 0 44px rgba(92,176,255,0.85),
        0 0 92px rgba(30,144,255,0.55);
    }
  }

  /* Booking-card title ("Tell us about your business") — bumped + glowing
     so the form section reads as deliberate, not a footer afterthought. */

  /* Booking lead paragraph — slightly larger, brighter, with a subtle glow
     so it doesn't look like a quiet footnote next to the loud headline. */
  #booking .booking-lead {
    font-size: 18px;
    line-height: 1.65;
    color: var(--ice);
    text-shadow:
      0 0 10px rgba(92,176,255,0.18),
      0 0 22px rgba(30,144,255,0.10);
  }

  /* The submit button itself — give it a stronger always-on glow so it
     feels like the obvious action, not just one button among many. */

  @media (prefers-reduced-motion: reduce) {
    #booking .section-tag span,
    #booking .display,
    #booking .display em {
      animation: none;
    }
  }

  /* ----- 05 WORK / FOUNDERS / CONTACT ----- */
  .work { padding-top: 18vh; padding-bottom: 12vh; }
  .work-card {
    position: relative; overflow: hidden;
    border: 1px solid var(--rule);
    background: linear-gradient(180deg, rgba(14,26,48,0.5), rgba(3,6,13,0.6));
    aspect-ratio: 4 / 3;
    display: flex; flex-direction: column; justify-content: flex-end;
    padding: 2rem; transition: border-color 0.5s var(--ease-out);
  }
  .work-card:hover { border-color: var(--blue-bright); }
  .work-card .visual {
    position: absolute; inset: 0; z-index: 0; opacity: 0.7;
    transition: opacity 0.6s var(--ease-out), transform 0.8s var(--ease-out);
  }
  .work-card:hover .visual { opacity: 1; transform: scale(1.04); }
  .work-card .visual.cabrera {
    background:
      radial-gradient(ellipse at 30% 40%, rgba(245,185,74,0.35) 0%, transparent 55%),
      radial-gradient(ellipse at 80% 80%, rgba(30,144,255,0.25) 0%, transparent 55%),
      linear-gradient(135deg, #1a1410 0%, #050912 100%);
  }
  .work-card .visual.amtiles {
    background:
      radial-gradient(ellipse at 70% 30%, rgba(124,92,255,0.3) 0%, transparent 55%),
      radial-gradient(ellipse at 20% 80%, rgba(30,144,255,0.3) 0%, transparent 55%),
      linear-gradient(135deg, #0e1a30 0%, #050912 100%);
  }
  .work-card:hover .arrow {
    background: var(--blue-bright); color: var(--obsidian);
    border-color: var(--blue-bright); transform: rotate(-45deg);
  }

  /* ----- 05 PROOF — pinned case deck -----
     Desktop: the section is exactly one viewport tall and gets pinned by
     ScrollTrigger; the intro, three cases, and the quote are absolutely
     stacked layers the scrub timeline swaps between (transform + opacity
     only — nothing here triggers layout or paint during scroll).
     Phones / reduced motion: the layers return to normal flow as stacked
     cards and the pin never happens (see initProofSection). */
  .proof {
    position: relative;
    height: 100vh;
    height: 100svh;
    overflow: hidden;
    display: grid;
    place-items: center;
  }
  .proof-intro {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 0 6vw;
    z-index: 2;
    /* Own layer from first paint. Its fade-out tween otherwise promotes it
       mid-scroll, and rastering this text-shadowed headline at that moment
       cost a 100ms frame on Intel GPUs (trace, 2026-10-01). */
    will-change: transform, opacity;
  }
  .proof-intro-sub {
    margin-top: 1.6rem;
    color: var(--ice-dim);
    font-size: clamp(0.95rem, 1.1vw, 1.1rem);
    letter-spacing: 0.04em;
  }
  .proof-case {
    position: absolute;
    inset: 0;
    display: grid;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    align-items: center;
    gap: clamp(2rem, 5vw, 5rem);
    max-width: 1340px;
    margin: 0 auto;
    padding: 0 clamp(1.5rem, 5vw, 4rem);
    opacity: 0;
    visibility: hidden; /* JS flips to visible; keeps first paint clean */
    z-index: 3;
  }
  .proof-copy { position: relative; z-index: 2; }
  .proof-index {
    font-family: var(--font-display);
    font-weight: 300;
    font-size: clamp(4.5rem, 9vw, 9rem);
    line-height: 1;
    color: transparent;
    -webkit-text-stroke: 1px rgba(92, 176, 255, 0.4);
    margin-bottom: 0.5rem;
  }
  .proof-name {
    font-family: var(--font-display);
    font-weight: 300;
    font-size: clamp(2rem, 3.6vw, 3.6rem);
    line-height: 1.02;
    letter-spacing: -0.02em;
    color: var(--ice);
  }
  .proof-name em {
    font-family: var(--font-serif);
    font-style: italic;
    font-weight: 400;
    color: var(--blue-bright);
  }
  .proof-desc {
    margin-top: 1.4rem;
    max-width: 44ch;
    color: var(--ice-dim);
    font-size: clamp(0.98rem, 1.15vw, 1.12rem);
    line-height: 1.6;
  }
  .proof-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    margin-top: 1.8rem;
    padding: 0.55rem 1.1rem;
    border: 1px solid rgba(92, 176, 255, 0.35);
    border-radius: 999px;
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ice-dim);
  }
  .proof-chip-dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--blue-bright);
    box-shadow: 0 0 10px var(--blue-bright);
  }
  .proof-media {
    position: relative;
    aspect-ratio: 16 / 10;
    border-radius: 14px;
    overflow: hidden;
    border: 1px solid rgba(232, 238, 245, 0.14);
    background: #04070d;
    box-shadow:
      0 30px 80px rgba(0, 0, 0, 0.55),
      0 0 60px rgba(30, 144, 255, 0.12);
    transform-style: preserve-3d;
    will-change: transform;
  }
  .proof-media video,
  .proof-media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
    display: block;
  }
  /* Faint screen-glass sheen over the media */
  .proof-media::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(160deg, rgba(232,238,245,0.10) 0%, transparent 34%);
    pointer-events: none;
  }
  .proof-quote {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    max-width: 62ch;
    margin: 0 auto;
    padding: 0 6vw;
    opacity: 0;
    visibility: hidden;
    z-index: 4;
  }
  .proof-stars { display: flex; gap: 0.6rem; margin-bottom: 2rem; }
  .proof-star {
    font-size: clamp(1.3rem, 2vw, 1.9rem);
    color: var(--gold, #f5b94a);
    text-shadow: 0 0 18px rgba(245, 185, 74, 0.55);
  }
  .proof-quote blockquote {
    font-family: var(--font-serif);
    font-style: italic;
    font-weight: 400;
    font-size: clamp(1.3rem, 2.4vw, 2.1rem);
    line-height: 1.4;
    color: var(--ice);
  }
  /* The second half of each review is verbatim and stays verbatim — it is
     folded behind a disclosure so the finale opens with the punchy first
     paragraph instead of a ~200-word wall of 12.8px type. */
  .proof-more {
    margin-top: 1.4rem;
  }
  .proof-more > summary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    list-style: none;
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ice-dim);
    transition: color 0.3s var(--ease-out);
  }
  .proof-more > summary::-webkit-details-marker { display: none; }
  .proof-more > summary::after {
    content: '+';
    font-size: 13px;
    line-height: 1;
    color: var(--blue-bright);
  }
  .proof-more[open] > summary::after { content: '\2212'; }
  .proof-more > summary:hover { color: var(--ice); }
  .proof-quote-more {
    margin-top: 1.6rem;
    max-width: 56ch;
    font-size: clamp(0.9rem, 1.1vw, 1.05rem);
    line-height: 1.7;
    color: var(--ice-dim);
  }
  .proof-quote figcaption {
    margin-top: 2rem;
    font-size: 11px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--ice-dim);
  }
  .proof-quote figcaption span { color: var(--ice-faint); }

  /* Multi-review wrapper — desktop: absolute overlay like the old single quote.
     Mobile: normal flow, stacked vertically. */
  .proof-reviews {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    z-index: 4;
    opacity: 0;
  }
  /* Desktop: the two reviews cross-fade in the same spot, so they stack on
     top of each other rather than flowing one under the other (stacked, the
     pair ran ~1500px tall inside a 900px pinned stage and the second review
     was pushed off-screen). `visibility: visible` is required — the base
     .proof-quote rule hides them, and without this the whole review finale
     was invisible on laptops even though the timeline was running. */
  .proof-reviews .proof-quote {
    position: absolute;
    inset: 0;
    margin: 0 auto;
    opacity: 0;
    visibility: visible;
    max-width: 70ch;
    padding: 0 6vw;
  }
  /* Type was shrunk here so the longest review fit a 900px pinned stage. With
     the second half folded behind .proof-more only the first paragraph shows,
     so it can read at a normal size again. Copy is verbatim and never trimmed. */
  @media (min-width: 801px) {
    .proof-reviews .proof-stars { margin-bottom: 1.1rem; }
    .proof-reviews blockquote {
      font-size: clamp(1.2rem, 1.65vw, 1.7rem);
      line-height: 1.45;
    }
    .proof-reviews .proof-quote-more {
      margin-top: 1rem;
      max-width: 68ch;
      font-size: clamp(0.92rem, 1vw, 1.05rem);
      line-height: 1.6;
    }
    .proof-reviews .proof-quote figcaption { margin-top: 1.1rem; }
  }

  .proof-counter {
    position: absolute;
    left: clamp(1.5rem, 4vw, 3rem);
    bottom: 3rem;
    font-size: 12px;
    letter-spacing: 0.3em;
    color: var(--ice-faint);
    opacity: 0;
    z-index: 5;
  }
  #proof-counter-num { color: var(--blue-bright); }

  /* Phone — sticky stage. Each case holds still under the thumb while the
     next card scrolls up over it; the two reviews hand off the same way.

     Why sticky rather than the desktop pin: an unpinned card is already
     translating with the page at 800-1500px per thumb flick, so its own
     transform is perceptually subtracted — which is why the earlier
     "make the drift bigger" pass still read as no animation at all. Sticky
     buys the same stationary reference frame a pin does, but with no pin
     spacer for iOS's address-bar resize to invalidate, no second layout
     mode, and no second scroll driver. The scrub work then rides on one
     non-sticky ScrollTrigger anchored to #work (see initProofSection).

     Also serves as the no-JS layout. */
  @media (max-width: 800px) {
    .proof {
      height: auto;
      overflow: visible;
      display: block;
      padding: 16vh 0 6vh;
    }
    .proof-intro {
      position: relative;
      inset: auto;
      padding: 0 6vw 10vh;
    }
    /* The centred tags sat flush on their headlines (0px) on phones. */
    .proof .section-tag, .about-hero .section-tag { margin-bottom: 1rem; }
    .proof-case {
      position: sticky;
      inset: auto;
      top: 0;
      grid-template-columns: 1fr;
      align-content: center;
      min-height: 92svh;
      gap: 1.6rem;
      opacity: 1;
      visibility: visible;
      padding: 0 6vw;
      margin-bottom: 18svh;
    }
    .proof-index { font-size: 3.4rem; margin-bottom: 0.2rem; }
    .proof-reviews {
      position: relative;
      inset: auto;
      display: block;
      opacity: 1;
      visibility: visible;
      padding: 4vh 6vw 0;
    }
    .proof-reviews .proof-quote {
      position: sticky;
      inset: auto;
      top: 0;
      min-height: 68svh;
      opacity: 1;
      visibility: visible;
      max-width: none;
      padding: 0;
      margin-bottom: 10svh;
    }
    /* Last review has nothing to hold over — its 68svh min-height left a
       ~300px empty gap before Process (Kade, 2026-10-12). */
    .proof-reviews .proof-quote:last-child { margin-bottom: 0; min-height: auto; }
    /* Each held screen used to have to swallow a whole review, so the type was
       squeezed to 12.8px. Only the first paragraph shows now — the rest sits
       behind .proof-more — so it reads at a normal size. Copy stays verbatim. */
    .proof-reviews .proof-stars { margin-bottom: 1rem; }
    .proof-reviews blockquote { font-size: 1.22rem; line-height: 1.42; }
    .proof-reviews .proof-quote-more {
      margin-top: 0.9rem;
      font-size: 0.95rem;
      line-height: 1.55;
    }
    .proof-reviews .proof-quote figcaption { margin-top: 1.1rem; }
    .proof-counter { display: none; }
  }

  /* Reduced motion at any width — same stacked flow as phones, pure CSS so
     it holds even before/without JS. The pin timeline is skipped in JS. */
  @media (prefers-reduced-motion: reduce) {
    .proof {
      height: auto;
      overflow: visible;
      display: block;
      padding: 16vh 0 6vh;
    }
    .proof-intro { position: relative; inset: auto; padding: 0 6vw 10vh; }
    /* min-height/margin reset undoes the phone sticky stage above, which is
       still in force at <=800px — reduced motion gets compact static cards. */
    .proof-case {
      position: relative;
      inset: auto;
      min-height: auto;
      opacity: 1;
      visibility: visible;
      margin-bottom: 12vh;
    }
    .proof-reviews {
      position: relative;
      inset: auto;
      opacity: 1;
      visibility: visible;
      padding: 4vh 6vw 0;
    }
    .proof-reviews .proof-quote {
      position: relative;
      inset: auto;
      min-height: auto;
      opacity: 1;
      visibility: visible;
      padding: 0;
      margin-bottom: 6vh;
    }
    .proof-counter { display: none; }
  }

  /* ----- CTA banner (replaces old founders section) ----- */
  .cta-banner {
    padding-top: 14vh;
    padding-bottom: 14vh;
    text-align: center;
    position: relative;
  }
  .cta-banner-inner {
    max-width: 1100px;
    margin: 0 auto;
    border-top: 1px solid var(--rule);
    padding-top: 4rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2.4rem;
  }
  .cta-banner .section-tag {
    justify-content: center;
  }
  .cta-banner-headline {
    margin-top: 1rem;
    line-height: 1.05;
    text-align: center;
  }
  .cta-banner-headline em {
    font-family: var(--font-serif);
    font-style: italic;
    background: linear-gradient(180deg, #5cb0ff 0%, #1e90ff 60%, #7c5cff 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  .cta-banner-link {
    display: inline-flex;
    align-items: center;
    gap: 0.8rem;
    padding: 1.1rem 2.2rem;
    background: linear-gradient(90deg, var(--blue), var(--blue-deep));
    color: white;
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    border-radius: 999px;
    box-shadow:
      0 6px 24px rgba(30, 144, 255, 0.45),
      inset 0 1px 0 rgba(255, 255, 255, 0.2);
    transition: transform 0.4s var(--ease-out),
                box-shadow 0.4s var(--ease-out);
    text-decoration: none;
    margin-top: 0.4rem;
  }
  .cta-banner-link:hover {
    transform: translateY(-2px);
    box-shadow:
      0 10px 32px rgba(30, 144, 255, 0.6),
      inset 0 1px 0 rgba(255, 255, 255, 0.3);
  }
  .cta-banner-link .arrow {
    transition: transform 0.4s var(--ease-out);
  }
  .cta-banner-link:hover .arrow {
    transform: translateX(4px);
  }

  .contact {
    padding-top: 14vh; padding-bottom: 12vh;
    text-align: center; position: relative;
  }
  .contact-mail {
    display: inline-block;
    font-family: var(--font-display); font-weight: 300;
    font-size: clamp(2.4rem, 8vw, 7rem); line-height: 1;
    letter-spacing: -0.04em; color: var(--ice); position: relative;
    transition: color 0.4s var(--ease-out);
  }
  .contact-mail em {
    font-family: var(--font-serif); color: var(--blue-bright); font-style: italic;
  }
  .contact-mail::after {
    content: ""; display: block; width: 100%; height: 1px;
    background: var(--blue-bright); margin: 1rem auto 0;
    transform: scaleX(0); transform-origin: center;
    transition: transform 0.6s var(--ease-out);
  }
  .contact-mail:hover::after { transform: scaleX(1); }

  /* ----- BOOKING ----- */
  .booking {
    /* 2026-08-31: left at 18vh deliberately. .section-num is absolutely
       positioned at top:6vh and is ~88px tall, so the in-flow .section-tag
       needs ~16vh of padding to clear it. Cutting this to 12vh collided
       "BOOKING" with "BOOK A CALL". The fold space is recovered from
       .booking-grid and the removed duplicate h3 instead. The 170px floor
       covers short viewports, where 18vh alone left only 1px of clearance
       (1280x720 measured). */
    padding-top: max(18vh, 170px); padding-bottom: 14vh;
    position: relative;
  }
  .booking-grid {
    /* 2026-08-31: 6rem -> 1.5rem. This gap, and the removed duplicate h3, are
       where the fold space comes from — the section's own padding-top can't be
       cut without colliding .section-tag into .section-num. */
    margin-top: 1.5rem;
    display: grid;
    /* 2026-08-25: calendar column first and wider — the GHL widget needs room
       for a month grid plus a slot list, and it's now the lead element. */
    grid-template-columns: 1.35fr 0.85fr;
    gap: 4vw;
    align-items: start;
  }
  @media (max-width: 900px) {
    .booking-grid { grid-template-columns: 1fr; gap: 3rem; }
  }
  .booking-lead {
    font-size: clamp(1.1rem, 1.5vw, 1.4rem);
    line-height: 1.5;
    color: var(--ice-dim);
    max-width: 44ch;
    margin-bottom: 2.4rem;
  }
  .booking-checks {
    list-style: none;
    padding: 0;
    border-top: 1px solid var(--rule);
  }
  .booking-checks li {
    padding: 1.2rem 0;
    border-bottom: 1px solid var(--rule);
    display: flex;
    align-items: center;
    gap: 1rem;
    color: var(--ice);
    font-size: 1rem;
    line-height: 1.4;
  }
  .booking-checks .check {
    width: 22px; height: 22px;
    border-radius: 50%;
    background: rgba(30, 144, 255, 0.15);
    color: var(--blue-bright);
    font-size: 11px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    border: 1px solid rgba(92, 176, 255, 0.4);
  }

  /* "Prefer to talk?" tap-to-call block — alternate path for non-form visitors. */
  .booking-call {
    margin-top: 2rem;
    padding: 1.4rem 1.6rem;
    border: 1px solid rgba(92, 176, 255, 0.25);
    border-radius: 14px;
    background: linear-gradient(180deg, rgba(14, 28, 52, 0.85), rgba(10, 20, 38, 0.9));
    transition: border-color 0.4s var(--ease-out),
                box-shadow 0.4s var(--ease-out);
  }
  .booking-call:hover {
    border-color: rgba(92, 176, 255, 0.55);
    box-shadow: 0 0 28px rgba(30, 144, 255, 0.18);
  }
  .booking-call-eyebrow {
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--ice-faint);
    margin-bottom: 0.6rem;
  }
  .booking-call-link {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    color: var(--ice);
    text-decoration: none;
    font-family: var(--font-display);
    font-size: clamp(1.1rem, 1.7vw, 1.4rem);
    letter-spacing: -0.01em;
    line-height: 1.2;
  }
  .booking-call-link svg {
    color: var(--blue-bright);
    filter: drop-shadow(0 0 8px rgba(92, 176, 255, 0.6));
    flex-shrink: 0;
  }
  .booking-call-link strong {
    font-weight: 500;
    color: var(--blue-bright);
    font-variant-numeric: tabular-nums;
    transition: color 0.3s var(--ease-out);
  }
  .booking-call-link:hover strong {
    color: #ffffff;
    text-shadow: 0 0 16px rgba(92, 176, 255, 0.8);
  }
  .booking-call-sub {
    margin-top: 0.6rem;
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--ice-dim);
    line-height: 1.5;
  }
  /* Past-client path. Deliberately quieter than .booking-call so it never
     competes with Book My Call — this is for people who already worked with
     us, not the prospect the section is built for. */
  .booking-review {
    margin-top: 1rem;
    padding: 0.9rem 1.6rem;
    border: 1px solid rgba(92, 176, 255, 0.14);
    border-radius: 14px;
    background: rgba(10, 20, 38, 0.55);
  }
  .booking-review-eyebrow {
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--ice-faint);
    margin-bottom: 0.4rem;
  }
  .booking-review-link {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-body);
    font-size: 14px;
    color: var(--ice-dim);
    text-decoration: none;
    transition: color 0.3s var(--ease-out);
  }
  .booking-review-link svg {
    color: var(--blue-bright);
    flex-shrink: 0;
  }
  .booking-review-link:hover { color: var(--ice); }
  .booking-review-link .arrow { transition: transform 0.3s var(--ease-out); }
  .booking-review-link:hover .arrow { transform: translateX(3px); }
  .booking-card {
    border: 1px solid var(--rule-bright);
    background: linear-gradient(180deg, rgba(14, 26, 48, 0.85), rgba(3, 6, 13, 0.75));
    border-radius: 14px;
    padding: 2.4rem;
    position: relative;
    overflow: hidden;
  }
  /* Calendar variant of the booking card. Declared AFTER .booking-card on
     purpose — same specificity, so source order is what makes the tighter
     padding win and keeps the embed from being squeezed. */
  .booking-card--calendar { padding: 1.1rem 1.4rem 1.4rem; overflow: visible; }
  .lead-catch {
    margin-top: 2rem;
    padding: 1.4rem 1.4rem 1.2rem;
    border: 1px solid var(--rule-bright);
    border-radius: 12px;
    background: rgba(10, 20, 38, 0.5);
  }
  .lead-catch-eyebrow {
    font-size: 0.72rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--blue-bright);
    margin-bottom: 0.45rem;
  }
  .lead-catch-lead {
    font-size: 0.86rem;
    line-height: 1.5;
    color: var(--ice-dim);
    margin: 0 0 0.9rem;
  }
  /* SMS consent at the opt-in point (A2P) — wording mirrors Privacy §11. */
  .lead-catch-consent {
    font-size: 0.72rem;
    line-height: 1.5;
    color: var(--ice-faint);
    margin: 0.7rem 0 0;
  }
  .lead-catch-consent a { color: var(--ice-dim); text-decoration: underline; }
  .lead-catch-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.6rem;
    margin-bottom: 0.6rem;
  }
  @media (max-width: 700px) {
    .lead-catch-row { grid-template-columns: 1fr; }
  }
  .lead-catch input {
    width: 100%;
    padding: 0.7rem 0.85rem;
    border-radius: 8px;
    border: 1px solid var(--rule-bright);
    background: rgba(3, 6, 13, 0.6);
    color: var(--ice);
    font-family: inherit;
    font-size: 0.9rem;
  }
  .lead-catch input::placeholder { color: rgba(200, 218, 245, 0.45); }
  .lead-catch input:focus {
    outline: none;
    border-color: var(--blue-bright);
  }
  .lead-catch-btn {
    margin-top: 0.35rem;
    width: 100%;
    padding: 0.75rem 1rem;
    border-radius: 8px;
    border: 1px solid var(--blue-bright);
    background: rgba(59, 130, 246, 0.14);
    color: var(--ice);
    font-family: inherit;
    font-size: 0.88rem;
    letter-spacing: 0.04em;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    transition: background 0.25s ease;
  }
  .lead-catch-btn:hover { background: rgba(59, 130, 246, 0.26); }
  .lead-catch-btn[disabled] { opacity: 0.6; cursor: default; }
  .lead-catch-status {
    margin-top: 0.55rem;
    font-size: 0.8rem;
    min-height: 1.1rem;
    color: var(--ice-dim);
  }
  .lead-catch-status.is-ok { color: var(--blue-bright); }
  .lead-catch-status.is-error { color: #ff8a8a; }
  /* Declared AFTER the base .lead-catch input rules on purpose — a media query
     adds no specificity, so a later plain rule would otherwise win (same trap
     that silently ate the calendar card padding). 16px is the floor: iOS Safari
     zooms the whole page in when a focused input is smaller, throwing the
     visitor out of the layout mid-form. The taller padding also lifts the tap
     target to Apple's 44px minimum. */
  @media (max-width: 700px) {
    .lead-catch input { font-size: 16px; padding: 0.8rem 0.85rem; }
    .lead-catch-btn { font-size: 16px; padding: 0.85rem 1rem; }
  }
  .booking-steps {
    list-style: none;
    /* 2026-08-31: 1.1rem -> 0.7rem top, same reason. */
    margin: 0.7rem 0 0.2rem;
    padding: 0;
    display: grid;
    gap: 0.5rem;
  }
  .booking-steps li {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    font-size: 0.9rem;
    line-height: 1.45;
    color: var(--ice-dim);
  }
  .booking-steps li span {
    flex: 0 0 auto;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    border: 1px solid var(--rule-bright);
    display: grid;
    place-items: center;
    font-size: 0.72rem;
    color: var(--blue-bright);
  }
  .booking-steps li strong { color: var(--ice); }
  .booking-embed {
    margin-top: 0.4rem;
    border-radius: 10px;
    overflow: hidden;
    background: #fff;
  }
  .booking-embed iframe {
    display: block;
    width: 100%;
    /* Fixed height — tall enough for the month grid plus the slot list without
       the widget's own scrollbar doing the work on desktop. */
    height: 860px;
    border: 0;
  }
  @media (max-width: 900px) {
    /* Trim the card's side padding on phones so the rented calendar widget
       keeps as much of the 375px viewport as possible. */
    .booking-card--calendar { padding: 1rem 0.45rem 0.9rem; }
    .booking-embed iframe { height: 1020px; }
  }
  .booking-card::before {
    content: "";
    position: absolute;
    top: -1px; left: 0;
    width: 40%; height: 1px;
    background: var(--blue-bright);
    box-shadow: 0 0 8px var(--blue-bright);
  }
  .booking-card-eyebrow {
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: var(--ice-faint);
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }
  .booking-card-eyebrow::before {
    content: "";
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--blue-bright);
    box-shadow: 0 0 8px var(--blue-bright);
    animation: pulse 1.6s ease-in-out infinite;
  }
  .slot {
    border-bottom: 1px solid var(--rule);
    padding: 1rem 0;
    display: grid;
    grid-template-columns: 50px 1fr auto;
    align-items: center;
    gap: 1rem;
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.1em;
    color: var(--ice-dim);
  }

  /* ----- Booking form ----- */

  /* ----- Footer -----
     Privacy + Terms live on their own pages (linked under Explore) since
     2026-10-01 — 827 words of legal text no longer sit on the homepage. */
  .site-footer {
    border-top: 1px solid var(--rule);
    /* Bottom clears the fixed Call/Book bar (~71px on phones); a shorthand
       here once overrode the 96px set by the sticky-bar block and hid the
       copyright line under the bar. */
    padding: 2.4rem 5vw 96px;
    margin-top: 6vh;
    background: linear-gradient(180deg, transparent 0%, rgba(3,6,13,0.5) 100%);
  }
  /* ----- Footer contact block -----
     Where the business actually is, who it serves, and what it promises —
     the three things a stranger checks before they call. */
  .footer-contact {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 2.4rem;
    padding: 2.2rem 0 2rem;
    border-top: 1px solid var(--rule);
    margin-top: 1.6rem;
  }
  .fc-col .fc-label {
    display: block;
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--blue-bright);
    margin-bottom: 0.9rem;
  }
  .fc-col p,
  .fc-col address {
    font-size: 13.5px;
    line-height: 1.7;
    color: var(--ice-faint);
    font-style: normal;
    margin: 0;
  }
  .fc-col a { color: var(--ice); border-bottom: 1px solid transparent; transition: border-color 0.25s ease, color 0.25s ease; }
  .fc-col a:hover { color: var(--blue-bright); border-bottom-color: var(--blue-bright); }
  .fc-contact-list { display: flex; flex-direction: column; gap: 0.45rem; font-size: 13.5px; }
  .fc-col .fc-owners { margin-top: 0.6rem; color: var(--ice-dim); }
  @media (max-width: 900px) {
    .footer-contact { grid-template-columns: repeat(2, 1fr); gap: 1.8rem; }
  }
  @media (max-width: 560px) {
    .footer-contact { grid-template-columns: 1fr; gap: 1.6rem; }
  }

  .footer-meta {
    border-top: 1px solid var(--rule);
    padding-top: 1.4rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.22em;
    color: var(--ice-faint);
    text-transform: uppercase;
    flex-wrap: wrap;
    gap: 0.8rem;
  }

  /* ============================================================
   * FORMATION LAYER — "from nothing" particle convergence
   * Light streaks gather inward toward the origin dot during Act 1.
   * ============================================================ */
  .formation {
    position: absolute; inset: 0; z-index: 2;
    pointer-events: none; opacity: 0;
    overflow: hidden;
  }

  /* Camera-style scan line that sweeps top→bottom during wireframe build */

  /* Browser becomes fullbleed — JS animates width/height/border-radius.
     We just remove the artificial cap and ensure children scale gracefully. */

  /* Atmospheric vignette inside the assembled site for cinematic depth */

  /* ----- Reduced motion ----- */
  @media (prefers-reduced-motion: reduce) {
    * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
  }

  /* =========================================================
     MOBILE OVERRIDES (final cascade pass).
     Placed last so they always beat any earlier base styles
     regardless of source order or specificity quirks.
     Targets the three "build" picture/text blocks and the
     two launch cards that were overflowing on phone.
     ========================================================= */
  @media (max-width: 700px) {
    /* Fix 3 — "Custom Built To Your Standards" pill: full-width box,
       smaller letters, less tracking so all 5 words fit in one line. */

    /* Fix 4 — "Built to outsell your competition" headline: widen the
       block and shrink the font so the whole sentence sits on one row. */

    /* Fix 2 — Build-stage cover cards (Lumberjays + HVAC): make them taller
       so the full website preview shows inside each frame. */

    /* Fix 5 — launch card 02 (Transforming Spaces / A M Tile) was
       cropping the leading T/S/I/L letters. Use contain so the entire
       hero shows; pin to the left so it never gets center-cropped. */

    /* Fix 1 — home-page SCROLL cue raised above Safari's bottom toolbar
       and the on-page HUD so visitors actually see the prompt. */
  }

  /* =====================================================================
     MOBILE OPTIMIZATION (added 2026-06-19) — declutter + scroll performance.
     Phones only (≤800px). Desktop is completely untouched.
     Goals: kill GPU-heavy blur (the main scroll-jank source), make text
     readable over the 3D, hide decorative/repetitive clutter, calm the type.
     ===================================================================== */
  @media (max-width: 800px) {
    /* Blur is the #1 cause of mobile scroll jank — remove it everywhere on
       phones. Also makes overlaid text far more legible. */
    * {
      backdrop-filter: none !important;
      -webkit-backdrop-filter: none !important;
    }

    /* Solid panels behind glassy text cards so copy reads cleanly */
    .about-deeper-block {
      background: rgba(8, 12, 22, 0.9) !important;
      box-shadow: none !important;
    }
    /* Lift key text off the busy 3D background for readability */
    .hero-headline, .about .display, .section-tag span {
      text-shadow: 0 2px 14px rgba(0, 0, 0, 0.85) !important;
    }

    /* Declutter: hide decorative + repetitive elements that crowd phones.
       (Marquee repeats the service list; floating cards repeat it again.) */
    .hero-card,
    .hero-card-right {
      display: none !important;
    }

    /* Calmer typography — the display type was overwhelming on small screens */
    .hero-headline {
      font-size: clamp(2.1rem, 11vw, 3rem) !important;
      line-height: 1.05 !important;
    }
    .display {
      font-size: clamp(1.8rem, 8vw, 2.4rem) !important;
      line-height: 1.1 !important;
    }
  }

  /* ===== 2026-09-23 conversion pass ===== */
  /* Price line in the hero — the number a "free" offer needs next to it. */
  .hero-price {
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(16px, 1.25vw, 19px);
    color: var(--ice-dim);
  }
  .hero-price strong { color: var(--gold); font-weight: 600; font-size: 1.2em; letter-spacing: -0.01em; }

  /* Trade samples */
  .samples { padding-top: 14vh; padding-bottom: 6vh; }
  .samples-title { margin-top: 1.6rem; }
  .samples-sub { color: var(--ice-dim); font-size: 15px; line-height: 1.6; margin-top: 1rem; max-width: 56ch; }
  .samples-grid {
    margin-top: 3rem; display: grid; gap: 1.2rem;
    grid-template-columns: repeat(4, 1fr);
  }
  @media (max-width: 1100px) { .samples-grid { grid-template-columns: 1fr 1fr; } }
  @media (max-width: 600px)  { .samples-grid { grid-template-columns: 1fr; } }
  .sample-card {
    display: block; text-decoration: none; color: var(--ice);
    border: 1px solid var(--rule); border-radius: 14px; overflow: hidden;
    background: rgba(5, 9, 18, 0.6);
    transition: transform 0.35s var(--ease-out), border-color 0.35s var(--ease-out);
  }
  .sample-card:hover { transform: translateY(-4px); border-color: var(--rule-bright); }
  .sample-shot { display: block; aspect-ratio: 16 / 10; overflow: hidden; }
  .sample-shot img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top; }
  .sample-meta {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: 14px 16px; border-top: 1px solid var(--rule);
  }
  .sample-trade { font-family: var(--font-display); font-size: 16px; }
  .sample-open {
    font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.16em;
    text-transform: uppercase; color: var(--blue-bright); white-space: nowrap;
  }

  /* Pricing + straight answers */
  .faq { padding-top: 14vh; padding-bottom: 10vh; }
  .faq-title { margin-top: 1.6rem; }
  .faq { position: relative; overflow-x: clip; }
  .faq-cta { margin-top: 2.4rem; }
  @media (prefers-reduced-motion: reduce) {
    .sample-card { transition: none; }
  }

  /* ===== Quick lists + 3D shapes (2026-10-01) =====
     Trades owners scan, they don't read: one question, one line. Each row
     carries its own glow (a static gradient and a lit dot — no filter, no
     animated shadow), and reveals() fades rows in as they arrive. */
  .vx-list {
    position: relative; z-index: 1;
    list-style: none; margin: 2.4rem 0 0; padding: 0;
    display: grid; gap: 0.7rem; max-width: 820px;
  }
  .vx-list li {
    display: grid; grid-template-columns: 10px minmax(0, 15rem) 1fr;
    align-items: baseline; gap: 0.4rem 1.1rem;
    padding: 1.05rem 1.3rem;
    border: 1px solid rgba(92, 176, 255, 0.16);
    border-radius: 12px;
    background:
      radial-gradient(130% 160% at 0% 50%, rgba(30, 144, 255, 0.13), transparent 58%),
      rgba(6, 10, 20, 0.6);
  }
  .vx-list li::before {
    content: ''; width: 8px; height: 8px; border-radius: 50%;
    align-self: center;
    background: var(--blue-bright);
    box-shadow: 0 0 8px var(--blue-bright), 0 0 20px rgba(30, 144, 255, 0.55);
  }
  .vx-list .q {
    font-family: var(--font-display);
    font-size: clamp(16px, 1.25vw, 19px);
    color: var(--ice);
  }
  .vx-list .a { color: var(--ice-dim); font-size: 15px; line-height: 1.55; }
  @media (max-width: 700px) {
    .vx-list li { grid-template-columns: 10px 1fr; }
    .vx-list .a { grid-column: 2; }
  }

  /* Glowing wireframe cube behind a list. The faces are painted once; only
     the cube's transform turns, so it runs on the compositor. Sleeps with its
     section (initAnimationSleep). Static on phones and for reduced motion. */
  .vx-shape {
    position: absolute; z-index: 0; pointer-events: none;
    width: 220px; height: 220px; perspective: 900px;
  }
  .vx-shape::before {
    content: ''; position: absolute; inset: -70%;
    background: radial-gradient(closest-side, rgba(30, 144, 255, 0.16), transparent);
  }
  .vx-shape--right { right: 8vw; top: 34%; }
  .vx-shape--left  { left: -260px; top: 4rem; width: 170px; height: 170px; }
  .vx-cube {
    position: absolute; inset: 0;
    transform-style: preserve-3d;
    animation: vxSpin 28s linear infinite;
  }
  .vx-cube i {
    position: absolute; inset: 0;
    border: 1px solid rgba(92, 176, 255, 0.5);
    background: rgba(30, 144, 255, 0.035);
    box-shadow: inset 0 0 28px rgba(30, 144, 255, 0.22);
  }
  .vx-shape     .vx-cube i:nth-child(1) { transform: translateZ(110px); }
  .vx-shape     .vx-cube i:nth-child(2) { transform: rotateY(180deg) translateZ(110px); }
  .vx-shape     .vx-cube i:nth-child(3) { transform: rotateY(90deg) translateZ(110px); }
  .vx-shape     .vx-cube i:nth-child(4) { transform: rotateY(-90deg) translateZ(110px); }
  .vx-shape     .vx-cube i:nth-child(5) { transform: rotateX(90deg) translateZ(110px); }
  .vx-shape     .vx-cube i:nth-child(6) { transform: rotateX(-90deg) translateZ(110px); }
  .vx-shape--left .vx-cube i:nth-child(1) { transform: translateZ(85px); }
  .vx-shape--left .vx-cube i:nth-child(2) { transform: rotateY(180deg) translateZ(85px); }
  .vx-shape--left .vx-cube i:nth-child(3) { transform: rotateY(90deg) translateZ(85px); }
  .vx-shape--left .vx-cube i:nth-child(4) { transform: rotateY(-90deg) translateZ(85px); }
  .vx-shape--left .vx-cube i:nth-child(5) { transform: rotateX(90deg) translateZ(85px); }
  .vx-shape--left .vx-cube i:nth-child(6) { transform: rotateX(-90deg) translateZ(85px); }
  @keyframes vxSpin {
    from { transform: rotateX(-22deg) rotateY(0deg); }
    to   { transform: rotateX(-22deg) rotateY(360deg); }
  }
  @media (max-width: 1100px) { .vx-shape--left { display: none; } }
  @media (max-width: 800px) {
    .vx-shape--right { right: -60px; top: 6rem; opacity: 0.45; }
    .vx-cube { animation: none; transform: rotateX(-22deg) rotateY(35deg); }
  }
  @media (prefers-reduced-motion: reduce) {
    .vx-cube { animation: none; transform: rotateX(-22deg) rotateY(35deg); }
  }
  /* The corner HUD sat on top of the calendar's date grid and the sample
     cards on phones. It is decoration; the content under it is the point. */
  @media (max-width: 800px) { .hud { display: none; } }
  /* Paused while their section is off-screen — see initAnimationSleep(). */
  .anim-asleep, .anim-asleep *, .anim-asleep *::before, .anim-asleep *::after {
    animation-play-state: paused !important;
  }
  /* The SVG globe is the no-WebGL fallback. Once the three.js globe is up it
     fades to opacity 0 — but it kept spinning underneath, re-laying out every
     ellipse each frame. Freeze it; the fade is a transition, so it still fades. */
  /* Weaker machines (quality tier 1+, see Quality in app.js): the glows stay,
     they just stop breathing — held at each pulse's resting value. Every one
     of these animated text-shadow or box-shadow, which re-lays out the text
     each frame. */
  .vx-lite #process .display, .vx-lite #work .display, .vx-lite #process .stage h3, .vx-lite #process .display em, .vx-lite #work .display em, .vx-lite #process .stage h3 em, .vx-lite #process .section-tag span, .vx-lite #booking .section-tag span, .vx-lite #booking .display, .vx-lite #booking .display em, .vx-lite nav .cta.is-urgent {
    animation: none !important;
  }
  .vx-lite #process .stage h3 {
    text-shadow: 0 0 6px rgba(92,176,255,0.30), 0 0 18px rgba(92,176,255,0.15), 0 0 36px rgba(30,144,255,0.08);
  }
  .vx-lite #process .stage h3 em {
    text-shadow: 0 0 8px rgba(124,92,255,0.40), 0 0 22px rgba(92,176,255,0.25), 0 0 44px rgba(30,144,255,0.12);
  }
  /* Big .display headlines already glow via their blurred .glow-clone. Their
     36-56px text-shadows on 100px+ type cost an 80-116ms raster the first time
     each one scrolled on screen (Intel trace, 2026-10-01) — so drop them here. */
  .vx-lite #process .display, .vx-lite #work .display, .vx-lite #booking .display,
  .vx-lite #process .display em, .vx-lite #work .display em, .vx-lite #booking .display em {
    text-shadow: none;
  }
  .vx-lite #process .section-tag span {
    color: var(--ice);
    text-shadow: 0 0 6px rgba(92,176,255,0.35), 0 0 18px rgba(92,176,255,0.18), 0 0 36px rgba(30,144,255,0.10);
  }
  .vx-lite #booking .section-tag span {
    color: var(--ice);
    text-shadow: 0 0 8px rgba(92,176,255,0.40), 0 0 22px rgba(92,176,255,0.20), 0 0 44px rgba(30,144,255,0.12);
  }

  /* ===== 2026-09-23 wording pass (council) ===== */
  .hero-proof-link { color: inherit; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; border-bottom: 1px solid transparent; transition: border-color 0.2s var(--ease-out); }
  .hero-proof-link:hover { border-bottom-color: var(--ice-faint); }
  .proof-desc a, .about-deeper-block p a { color: var(--blue-bright); text-decoration: none; white-space: nowrap; }
  .proof-desc a:hover, .about-deeper-block p a:hover { text-decoration: underline; }
  .about-deeper-block p a { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: rgba(92, 176, 255, 0.45); }
  .booking-deal {
    margin: 0 0 1.4rem; padding: 1rem 1.2rem; border-radius: 12px;
    border: 1px solid rgba(245, 185, 74, 0.35); background: rgba(245, 185, 74, 0.06);
    color: var(--ice); font-size: 15px; line-height: 1.55;
  }
  .booking-deal strong { color: var(--gold); }
  /* The "$250/month covers" card floated at the section's vertical centre.
     With the About headline cut to two lines the trust cards moved up under
     it; it now sits in the flow below them on every width, as phones had it. */
  .about-hero .hero-card-right { position: relative; right: auto; top: auto; transform: none; margin: 2.4rem auto 0; width: 240px; z-index: 2; }
