/* =============================================================================
   VB — Growth, Engineered.
   Palette, type and motion tokens are the single source of truth; the hex
   values come straight from build-brief.md section 1 and must not be swapped
   for lookalikes.
   ========================================================================== */

/* --- fonts ---------------------------------------------------------------- */
/* Space Grotesk, self-hosted from the Google Fonts CDN payload. It is a
   variable font, so one file covers 400-700. */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../fonts/space-grotesk-latin.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: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../fonts/space-grotesk-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --- tokens --------------------------------------------------------------- */
:root {
  /* brand — exact values from the brief */
  --bg:            #0A0A0A;
  --white:         #FFFFFF;
  --green:         #00FF9C;
  --green-hover:   #4DFFB8;
  --green-pressed: #00CC7D;
  --green-glow:    rgba(0, 255, 156, 0.35);

  /* derived neutrals. --text-2 and --text-3 are contrast-checked against --bg
     (7.6:1 and 5.4:1) so body and tag text clear WCAG AA comfortably. */
  --text-2: #A0A6A3;
  --text-3: #868E8A;

  /* frosted glass. The gradient fill plus the saturate() in the blur is what
     separates "glass" from "grey tile" — saturation pulls the ambient green
     through the pane instead of averaging it to neutral. */
  --glass-bg: linear-gradient(140deg,
                rgba(255, 255, 255, 0.11) 0%,
                rgba(255, 255, 255, 0.055) 42%,
                rgba(255, 255, 255, 0.03) 100%);
  --glass-bg-hover: linear-gradient(140deg,
                rgba(255, 255, 255, 0.15) 0%,
                rgba(0, 255, 156, 0.07) 55%,
                rgba(255, 255, 255, 0.04) 100%);
  --glass-blur: blur(22px) saturate(190%);
  --glass-border: rgba(255, 255, 255, 0.13);
  --glass-edge: linear-gradient(140deg,
                rgba(255, 255, 255, 0.55) 0%,
                rgba(255, 255, 255, 0.10) 34%,
                rgba(255, 255, 255, 0) 62%);
  --glass-edge-hover: linear-gradient(140deg,
                rgba(0, 255, 156, 0.85) 0%,
                rgba(0, 255, 156, 0.22) 38%,
                rgba(255, 255, 255, 0) 68%);
  --glass-shadow: 0 10px 34px rgba(0, 0, 0, 0.42),
                  inset 0 1px 1px rgba(255, 255, 255, 0.07);

  /* surfaces */
  --surface-1: rgba(255, 255, 255, 0.045);
  --surface-2: rgba(255, 255, 255, 0.075);
  --line:      rgba(255, 255, 255, 0.11);
  --line-2:    rgba(255, 255, 255, 0.18);
  --green-8:   rgba(0, 255, 156, 0.08);
  --green-15:  rgba(0, 255, 156, 0.15);
  --green-35:  rgba(0, 255, 156, 0.35);
  --green-55:  rgba(0, 255, 156, 0.55);

  /* type */
  --font: 'Space Grotesk', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* motion — custom curves; the CSS built-ins are too soft to read as intentional */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* layout */
  --gutter:  clamp(1.25rem, 5vw, 4.5rem);
  --maxw:    1180px;
  --nav-h:   63px;
  --radius:  16px;
  --radius-s: 10px;
}

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

html {
  /* `clip` (not `hidden`): `hidden` would make this a scroll container, which
     changes how fixed/anchored descendants resolve */
  overflow-x: clip;
  scroll-behavior: auto;
  /* small breathing room above anchor targets; no fixed header to clear */
  scroll-padding-top: 2rem;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--white);
  font-family: var(--font);
  font-size: clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);
  line-height: 1.65;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.025em;
  text-wrap: balance;
}

p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

a { color: var(--green); text-decoration: none; }

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

/* --- a11y helpers --------------------------------------------------------- */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.skip-link {
  position: fixed; top: 0; left: 50%;
  transform: translate(-50%, -120%);
  z-index: 1000;
  padding: 0.75rem 1.25rem;
  background: var(--green);
  color: #04160F;
  font-weight: 600;
  border-radius: 0 0 var(--radius-s) var(--radius-s);
  transition: transform 180ms var(--ease-out);
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

/* One visible focus treatment everywhere, so keyboard users get the same
   affordance the mouse gets from hover. */
:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
  border-radius: 4px;
}

/* =============================================================================
   LOADER
   ========================================================================== */
.loader {
  position: fixed; inset: 0; z-index: 999;
  display: grid; place-items: center;
  background: var(--bg);
  transition: opacity 500ms var(--ease-out), visibility 500ms var(--ease-out);
}
.loader[data-done] { opacity: 0; visibility: hidden; }

.loader__matrix {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px 14px;
  perspective: 800px;
}
.loader__digit {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 18px;
  line-height: 1.4;
  text-align: center;
  color: var(--green);
  text-shadow: 0 0 6px var(--green-glow);
  opacity: 0;
  animation: matrix-fall 1.6s var(--ease-in-out) infinite;
}
.loader__digit:nth-child(1) { animation-delay: 0ms; }
.loader__digit:nth-child(2) { animation-delay: 70ms; }
.loader__digit:nth-child(3) { animation-delay: 140ms; }
.loader__digit:nth-child(4) { animation-delay: 210ms; }
.loader__digit:nth-child(5) { animation-delay: 280ms; }
.loader__digit:nth-child(6) { animation-delay: 350ms; }
.loader__digit:nth-child(7) { animation-delay: 420ms; }
.loader__digit:nth-child(8) { animation-delay: 490ms; }
.loader__digit:nth-child(9) { animation-delay: 560ms; }

.loader__glow {
  position: absolute; inset: -60px;
  background: radial-gradient(circle, rgba(0,255,156,0.12) 0%, transparent 70%);
  animation: matrix-pulse 1.6s ease-in-out infinite;
}

@keyframes matrix-fall {
  0%        { transform: translateY(-22px) rotateX(70deg); opacity: 0; }
  25%, 70%  { transform: translateY(0) rotateX(0);         opacity: 0.9; }
  100%      { transform: translateY(22px) rotateX(-70deg); opacity: 0; }
}
@keyframes matrix-pulse {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 0.75; }
}

/* =============================================================================
   SHARED
   ========================================================================== */
.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: clamp(2.75rem, 5.5vh, 4.25rem); position: relative; }

/* --- ambient depth --------------------------------------------------------- */
/* Frosted glass only reads as glass if there is something behind it to refract.
   Against flat #0A0A0A a backdrop-filter produces flat #0A0A0A — i.e. a grey
   tile. Three real depth layers sit behind the glass surfaces: a soft far glow,
   a tilted mid-distance circuit grid, and a handful of near "nodes" — plus a
   cursor perspective. Layers move at different rates under the cursor (the
   nearer the layer, the more it shifts), which is the actual depth cue; the
   translate/tilt values themselves are written by the ambient-depth module in
   main.js and default to zero, so the layers sit still and correct if that
   script never runs (reduced motion, touch, or a script failure). */
.ambient {
  position: absolute;
  inset: -8% 0;
  z-index: -1;
  perspective: 1000px;
  pointer-events: none;
  overflow: hidden;
}

/* layer 1 — far: the original soft colour glow. Barely moves. */
.ambient__glow {
  position: absolute; inset: 0;
  transition: translate 500ms var(--ease-out);
  will-change: translate;
}
.ambient__glow::before,
.ambient__glow::after {
  content: '';
  position: absolute;
  border-radius: 50%;
  filter: blur(96px);
}
.ambient__glow::before {
  width: 46%; aspect-ratio: 1.3;
  top: 4%; left: 6%;
  background: radial-gradient(circle, rgba(0, 255, 156, 0.085) 0%, transparent 68%);
}
.ambient__glow::after {
  width: 42%; aspect-ratio: 1.1;
  bottom: 2%; right: 4%;
  background: radial-gradient(circle, rgba(0, 255, 156, 0.13) 0%, transparent 68%);
}
/* second, offset pair so the field is not obviously two blobs */
.ambient--alt .ambient__glow::before {
  top: auto; bottom: 8%; left: 34%;
  width: 38%;
  background: radial-gradient(circle, rgba(77, 255, 184, 0.085) 0%, transparent 70%);
}
.ambient--alt .ambient__glow::after {
  top: 6%; right: 22%; bottom: auto;
  width: 34%;
  background: radial-gradient(circle, rgba(0, 255, 156, 0.075) 0%, transparent 70%);
}

/* layer 2 — mid: a circuit grid on a fixed 3D tilt (so it reads as a plane
   receding into the section, not a flat pattern), plus a small extra tilt on
   top of that from the cursor position. */
.ambient__grid {
  position: absolute; inset: -20% -10%;
  background-image:
    linear-gradient(rgba(0, 255, 156, 0.13) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0, 255, 156, 0.13) 1px, transparent 1px);
  background-size: 64px 64px;
  transform: rotateX(55deg) rotateZ(-8deg) scale(1.5)
             rotateY(var(--tilt-y, 0deg)) rotateX(var(--tilt-x, 0deg));
  transform-origin: center 30%;
  mask-image: radial-gradient(60% 60% at 50% 40%, #000 0%, transparent 75%);
  -webkit-mask-image: radial-gradient(60% 60% at 50% 40%, #000 0%, transparent 75%);
  opacity: 0.65;
  transition: transform 260ms var(--ease-out);
  will-change: transform;
}

/* layer 3 — near: a few glowing points, the closest layer, so they get the
   largest parallax shift. Whichever one the cursor is nearest brightens, as if
   it noticed. */
.ambient__nodes {
  position: absolute; inset: 0;
  transition: translate 380ms var(--ease-out);
  will-change: translate;
}
.ambient__node {
  position: absolute;
  left: var(--nx); top: var(--ny);
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 15px 4px rgba(0, 255, 156, 0.45);
  transition: scale 220ms var(--ease-out), box-shadow 220ms ease;
}
.ambient__node[data-near] {
  scale: 1.8;
  box-shadow: 0 0 24px 7px rgba(0, 255, 156, 0.7);
}

.section__head { margin-bottom: clamp(2.5rem, 5vw, 4rem); }

.section__title {
  font-size: clamp(1.9rem, 1.2rem + 2.6vw, 3.1rem);
  margin-top: 0.5rem;
  max-width: 18ch;
}

.eyebrow--hero {
  font-size: clamp(1.1875rem, 1rem + 0.75vw, 1.5625rem);
  letter-spacing: 0.2em;
  font-weight: 600;
  text-shadow: 0 0 18px rgba(0, 255, 156, 0.45);
}

.eyebrow {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--green);
}

/* =============================================================================
   BUTTONS
   Primary = saturated green glass. Secondary = neutral glass with a green
   glow-blob that sweeps in on hover. They must never read as the same weight.
   ========================================================================== */
.btn {
  --blob: 0;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.8rem 1.4rem;
  border-radius: var(--radius-s);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  isolation: isolate;
  transition: transform 160ms var(--ease-out),
              border-color 220ms ease,
              box-shadow 220ms ease,
              background-color 220ms ease,
              color 220ms ease;
}
.btn:active { transform: scale(0.97); }

.btn--lg { padding: 1rem 1.9rem; font-size: 1.0625rem; }

/* the glow blob, shared by both variants at different intensities */
.btn::after {
  content: '';
  position: absolute;
  z-index: -1;
  left: 50%; top: 110%;
  width: 130%; aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--green) 0%, transparent 68%);
  opacity: 0;
  filter: blur(18px);
  transition: opacity 300ms ease, top 420ms var(--ease-out);
}

.btn--primary {
  background: rgba(0, 255, 156, 0.14);
  border: 1px solid var(--green-55);
  color: var(--green);
  box-shadow: 0 0 24px rgba(0, 255, 156, 0.18), inset 0 1px 0 rgba(255,255,255,0.06);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.btn--primary::after { opacity: 0.22; }

.btn--glass {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--white);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.12);
}

@media (hover: hover) and (pointer: fine) {
  .btn--primary:hover {
    background: rgba(0, 255, 156, 0.22);
    border-color: var(--green);
    color: var(--green-hover);
    box-shadow: 0 0 38px var(--green-glow), inset 0 1px 0 rgba(255,255,255,0.1);
  }
  .btn--primary:hover::after { opacity: 0.4; top: 60%; }

  .btn--glass:hover {
    border-color: var(--green-55);
    color: var(--green-hover);
    box-shadow: 0 0 26px rgba(0, 255, 156, 0.16);
  }
  .btn--glass:hover::after { opacity: 0.28; top: 65%; }
}

.btn--primary:active { background: rgba(0, 204, 125, 0.3); border-color: var(--green-pressed); }

/* =============================================================================
   NAV
   ========================================================================== */
/* No bar. The header is a fully transparent layer holding two floating things:
   the wordmark and a single toggle button. Because the nav collapses to a
   button at every width — not just on mobile — there is no strip of link text
   that could end up sitting on light content, so the header can stay pinned and
   keep the CTA reachable the whole way down the page. */
.nav-wrap {
  position: fixed; top: 0; left: 0; right: 0; z-index: 120;
  background: none;
  border: 0;
  pointer-events: none; /* the transparent layer must not eat hero clicks */
}
.nav-wrap > * { pointer-events: auto; }

.nav {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.1rem clamp(1.25rem, 3vw, 2.75rem);
}

.nav__logo { display: block; flex-shrink: 0; }
/* The wordmark's strokes are mid-grey; on near-black they need lifting to
   carry as a brand mark rather than a smudge. */
.nav__logo img,
.footer__brand img { filter: brightness(1.5); }
/* 58px, not the old 34px: the VR script is thinner-stroked than the old block
   monogram and got lost at the smaller size. */
.nav__logo img { width: auto; height: 58px; }

/* --- toggle button -------------------------------------------------------- */
.nav__toggle {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  margin-left: auto;
  border-radius: 14px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
  transition: border-color 220ms ease, box-shadow 220ms ease,
              transform 160ms var(--ease-out);
}
.nav__toggle:active { transform: scale(0.94); }

@media (hover: hover) and (pointer: fine) {
  .nav__toggle:hover {
    border-color: var(--green-35);
    box-shadow: 0 10px 34px rgba(0, 0, 0, 0.45), 0 0 26px rgba(0, 255, 156, 0.18);
  }
}

.nav__toggle-bars,
.nav__toggle-bars::before,
.nav__toggle-bars::after {
  display: block;
  width: 18px; height: 1.5px;
  background: var(--white);
  border-radius: 2px;
  transition: transform 240ms var(--ease-out), background-color 160ms ease;
}
.nav__toggle-bars { position: relative; }
.nav__toggle-bars::before,
.nav__toggle-bars::after { content: ''; position: absolute; left: 0; }
.nav__toggle-bars::before { top: -6px; }
.nav__toggle-bars::after  { top: 6px; }

/* open state: the bars collapse into a cross */
.nav__toggle[aria-expanded="true"] .nav__toggle-bars { background: transparent; }
.nav__toggle[aria-expanded="true"] .nav__toggle-bars::before { transform: translateY(6px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__toggle-bars::after  { transform: translateY(-6px) rotate(-45deg); }

/* --- disclosure panel ----------------------------------------------------- */
/* Scales out of the button it belongs to, not from its own centre. */
.nav__menu {
  position: absolute;
  top: calc(100% + 0.55rem);
  right: clamp(1.25rem, 3vw, 2.75rem);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.25rem;
  width: max-content;
  min-width: 236px;
  padding: 0.7rem;
  border-radius: var(--radius);
  background: rgba(14, 15, 14, 0.92);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  box-shadow: 0 22px 54px rgba(0, 0, 0, 0.62);
  opacity: 0;
  transform: translateY(-8px) scale(0.97);
  transform-origin: top right;
  pointer-events: none;
  transition: opacity 190ms var(--ease-out), transform 190ms var(--ease-out);
}
.nav__menu[data-open] { opacity: 1; transform: none; pointer-events: auto; }

.nav__links { display: flex; flex-direction: column; gap: 0; }
.nav__links a {
  display: block;
  padding: 0.65rem 0.7rem;
  border-radius: 9px;
  color: var(--white);
  font-size: 1rem;
  font-weight: 500;
  transition: color 200ms ease, background-color 200ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .nav__links a:hover {
    color: var(--green-hover);
    background: rgba(255, 255, 255, 0.06);
  }
}

.nav__cta { width: 100%; margin-top: 0.45rem; }

/* =============================================================================
   HERO
   The brief asks for a full-bleed portrait. A true object-fit:cover across a
   16:9 viewport crops the head off a 0.8-ratio portrait, so the image is
   anchored as a full-height right-hand column and feathered into the page
   background — the photo's own vignette is already near-black, so it reads as
   full-bleed without decapitating the subject.
   ========================================================================== */
.hero {
  position: relative;
  /* the nav is fixed and overlays this section, so the hero owns the full
     viewport and just pads its content clear of the bar */
  min-height: min(100svh, 900px);
  display: flex;
  align-items: flex-end;
  padding: calc(var(--nav-h) + 3rem) var(--gutter) clamp(3rem, 7vh, 5rem);
  overflow: hidden;
  isolation: isolate;
}

/* Screen-blended over the flat #0A0A0A so only the green nodes/lines show —
   its own background is near-black, so without the blend it would paint a
   visible rectangle instead of merging into the page. */
.hero__plexus {
  position: absolute; z-index: -3;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: 0.85;
}
.hero__plexus img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: right center;
}

.hero__media {
  position: absolute;
  z-index: -2;
  top: 0; right: 0; bottom: 0;
  /* 95% of the original min(64vw, 820px) — shrinks the still image and the 3D
     canvas together in one place, since both fill this box exactly. */
  width: min(60.8vw, 779px);
}

/* Soft contact shadow so the robot reads as standing on something rather
   than floating — a dark ellipse is close to invisible on flat #0A0A0A, but
   the plexus background gives it a lighter area to actually cast onto. */
.hero__robot-shadow {
  position: absolute;
  left: 50%; bottom: 9%;
  width: 46%; aspect-ratio: 3 / 1;
  translate: -50% 0;
  background: radial-gradient(ellipse closest-side, rgba(0, 0, 0, 0.6) 0%, transparent 75%);
  filter: blur(2px);
  pointer-events: none;
}

/* The still and the canvas occupy the same box and are both `contain`, so the
   3D render lines up with the image it replaces and there is no jump at the
   moment the canvas takes over. */
.hero__robot-still,
.hero__robot {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  /* 44%, not 50%: centred read as sitting low in the empty column, but the
     first attempt (38%) went too far the other way. This only moves the
     still — the canvas has no letterboxing to reposition (its buffer already
     matches the box exactly), so the live 3D render is framed up instead, in
     robot-hero.js. */
  object-position: 50% 44%;
}

/* Painted over the still only once the first frame has actually rendered —
   until then (or forever, if WebGL or the module is unavailable) the WebP is
   what shows. */
.hero__robot {
  opacity: 0;
  transition: opacity 420ms var(--ease-out);
}
.hero__robot[data-ready] { opacity: 1; }

/* The canvas is transparent, so the still underneath would otherwise render
   straight through it as a second, offset robot. It cross-fades out as the
   canvas fades in. */
.hero__robot-still { transition: opacity 420ms var(--ease-out); }
.hero__media[data-3d] .hero__robot-still { opacity: 0; }

.hero__scrim {
  position: absolute; inset: 0; z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(to right,
      var(--bg) 0%, rgba(10,10,10,0.94) 26%, rgba(10,10,10,0.55) 48%, transparent 72%),
    linear-gradient(to top,
      var(--bg) 0%, rgba(10,10,10,0.7) 18%, transparent 52%);
}

/* Bottom-anchored by the flex container, then nudged up off the very edge —
   sitting flush against the bottom padding read as glued to the floor. */
.hero__content { position: relative; max-width: 42rem; margin-bottom: 2.25rem; }

.hero__title {
  font-size: clamp(3rem, 1.6rem + 6.6vw, 6.2rem);
  font-weight: 700;
  line-height: 0.94;
  letter-spacing: -0.04em;
  margin: 0.6rem 0 1.25rem;
}

.hero__sub {
  max-width: 34rem;
  color: var(--text-2);
  font-size: clamp(1rem, 0.94rem + 0.35vw, 1.1875rem);
}

.hero__cta { display: flex; flex-wrap: wrap; gap: 0.85rem; margin-top: 2rem; }

/* =============================================================================
   ABOUT
   ========================================================================== */
/* Copy only since the rebrand — the portrait column is gone. Left-aligned at
   the container's full width read as a ragged block stranded on the left with
   empty space dumped on the right; centred with a narrower, readable measure
   splits that space evenly on both sides instead, which reads as deliberate. */
.about__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  justify-items: center;
  text-align: center;
}
.about__text { max-width: 44rem; margin-inline: auto; }
.about__text .eyebrow { display: block; }

.about__body { margin-top: 1.5rem; }

.about__lead {
  font-size: clamp(1.05rem, 0.92rem + 0.6vw, 1.4rem);
  line-height: 1.65;
  letter-spacing: -0.015em;
}

/* JS wraps each word in .w and each character inside it in .c. The word stays
   inline-block so it never breaks mid-word across lines; the characters inside
   are what actually move.

   `transform` has no CSS transition — the JS manually eases position every
   frame and writes the already-interpolated value directly (same pattern as
   the hero reveal / cursor trail). A CSS transition retargeted on every single
   mousemove never settles into one coherent curve and reads as stutter even at
   a full frame rate; only the glow (color/text-shadow), a discrete on/off
   toggle rather than a continuous chase, gets a short transition. */
.about__lead .w { display: inline-block; white-space: nowrap; }
.about__lead .c {
  display: inline-block;
  transition: color 160ms ease, text-shadow 160ms ease;
}
.about__lead .c[data-near] {
  color: var(--green);
  text-shadow: 0 0 16px var(--green-glow);
}

/* --- experience timeline -------------------------------------------------- */
/* Static by spec. The rule is drawn once across the whole row rather than as a
   segment per item, so the three nodes always land on one continuous line
   regardless of how unevenly the copy below them wraps. */
.timeline {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  margin-top: clamp(3rem, 6vw, 4.5rem);
  padding-top: 1.75rem;
  counter-reset: milestone;
}
.timeline::before {
  content: '';
  position: absolute;
  top: 4px;
  /* full width with faded ends — gap-independent, so the rule always meets the
     node centres regardless of how the columns resolve */
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(to right,
    transparent 0%, var(--line-2) 16%, var(--line-2) 84%, transparent 100%);
}

.timeline__item { position: relative; }
/* the node */
.timeline__item::before {
  content: '';
  position: absolute;
  top: -21px;
  left: 50%;
  translate: -50% 0;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 12px 3px rgba(0, 255, 156, 0.4);
}

.timeline__title {
  font-size: 1rem;
  letter-spacing: -0.015em;
  text-align: center;
}
.timeline__text {
  margin-top: 0.4rem;
  color: var(--text-3);
  font-size: 0.8125rem;
  line-height: 1.55;
  text-align: center;
  text-wrap: pretty;
}

/* No left-border quote treatment: that read fine against left-aligned text
   but sat lopsided once the block centred — a rule on one side of centred
   text looks like a mistake, not an accent. Weight/size carries the hierarchy
   between this and the lead instead. */
.about__note {
  max-width: 38rem;
  margin: 1.25rem auto 0;
  color: var(--text-3);
  font-size: 0.9375rem;
  line-height: 1.6;
}
.about__note + .about__note { margin-top: 0.85rem; }

/* =============================================================================
   SERVICES
   7 cards on a 24-column grid: 3 wide cards, then 4 narrower ones. Reading
   order matches the brief exactly; the two-tier sizing gives the row some
   editorial rhythm instead of a flat 7-up wall.
   ========================================================================== */
.services__grid {
  display: grid;
  grid-template-columns: repeat(24, 1fr);
  gap: clamp(0.75rem, 1.4vw, 1.15rem);
  align-items: stretch;
}
/* The slot is the grid item; .card inside it is the visual surface. The slot
   supplies the perspective for the card's rotate-based tilt. */
.card-slot { display: flex; min-width: 0; perspective: 800px; }
.card-slot[data-row="1"] { grid-column: span 8; }
.card-slot[data-row="2"] { grid-column: span 6; }
.card-slot > .card { flex: 1; min-width: 0; }

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding: clamp(1.25rem, 2vw, 1.75rem);
  border-radius: var(--radius);
  overflow: hidden;
  /* `rotate`, not `transform`: anime.js owns transform on these during the
     expand-on-hover reflow. */
  transition: border-color 280ms ease, box-shadow 280ms ease,
              rotate 220ms var(--ease-out);
  /* frosted pane — see --glass-* tokens */
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
}

/* Green wash that fades in behind the content on hover. */
.card::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 12% 0%, var(--green-8) 0%, transparent 62%);
  opacity: 0;
  transition: opacity 320ms ease;
  pointer-events: none;
}

/* Specular edge: a bright hairline along the top-left, fading away by the
   bottom-right, the way light catches the lip of a real pane. */
.card::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: var(--glass-edge);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}

.card__icon {
  display: grid;
  place-items: center;
  width: 52px; height: 52px;
  border-radius: 13px;
  background: rgba(0, 255, 156, 0.07);
  border: 1px solid var(--green-15);
  margin-bottom: 0.35rem;
  overflow: hidden;
}
/* The icon PNGs are neon artwork on an opaque black square. `screen` drops the
   black entirely so only the glow lands on the glass. The artwork carries a
   wide margin inside its own frame, so it is scaled up past the box and
   clipped rather than sitting as a speck in the middle. */
.card__icon img {
  width: 52px; height: 52px;
  scale: 1.35;
  mix-blend-mode: screen;
}

.card__title { font-size: 1.0625rem; letter-spacing: -0.02em; }

.card__desc {
  color: var(--text-2);
  font-size: 0.9rem;
  line-height: 1.6;
  flex: 1;
}

.tags { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.4rem; }
.tags li {
  padding: 0.2rem 0.55rem;
  border-radius: 100px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--line);
  color: var(--text-3);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1.5;
  white-space: nowrap;
  transition: color 260ms ease, border-color 260ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .card:hover {
    background: var(--glass-bg-hover);
    border-color: var(--green-35);
    box-shadow: 0 14px 44px rgba(0, 0, 0, 0.5),
                0 0 44px rgba(0, 255, 156, 0.16),
                inset 0 1px 1px rgba(255, 255, 255, 0.12);
  }
  .card:hover::before { opacity: 1; }
  .card:hover::after { background: var(--glass-edge-hover); }
  .card:hover .tags li { color: var(--text-2); border-color: rgba(0,255,156,0.22); }
}
.card:focus-within {
  border-color: var(--green-35);
  background: var(--glass-bg-hover);
}
.card:focus-within::after { background: var(--glass-edge-hover); }

/* =============================================================================
   HOW I WORK
   Numbered steps on the same glass system as the service cards, but flatter —
   this section is a sequence to read, not a grid to explore, so it gets no
   tilt, no expand, no hover reflow.
   ========================================================================== */
.process__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(0.85rem, 1.5vw, 1.15rem);
  counter-reset: step;
}

.process__step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: clamp(1.25rem, 2vw, 1.6rem);
  border-radius: var(--radius);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
  counter-increment: step;
  transition: border-color 260ms ease, box-shadow 260ms ease;
}
.process__step::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: var(--glass-edge);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}
/* step number, sits quietly in the corner */
.process__step::before {
  content: '0' counter(step);
  position: absolute;
  top: clamp(1.25rem, 2vw, 1.6rem);
  right: clamp(1.25rem, 2vw, 1.6rem);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--green);
  opacity: 0.5;
}

.process__icon {
  display: grid;
  place-items: center;
  width: 52px; height: 52px;
  border-radius: 13px;
  background: rgba(0, 255, 156, 0.07);
  border: 1px solid var(--green-15);
  overflow: hidden;
}
/* same neon-on-opaque-black artwork as the service icons */
.process__icon img {
  width: 52px; height: 52px;
  scale: 1.35;
  mix-blend-mode: screen;
}

.process__title { font-size: 1.0625rem; letter-spacing: -0.02em; }
.process__text {
  color: var(--text-2);
  font-size: 0.875rem;
  line-height: 1.6;
}

@media (hover: hover) and (pointer: fine) {
  .process__step:hover { border-color: var(--green-35); box-shadow: 0 12px 38px rgba(0,0,0,0.45), 0 0 30px rgba(0,255,156,0.12); }
  .process__step:hover::after { background: var(--glass-edge-hover); }
}

/* =============================================================================
   TOOLS I USE
   Text-only badges. No third-party brand logos — trademark constraint.
   ========================================================================== */
/* Two fixed columns, not natural-width flex-wrap: flex packed each row to fit
   as many groups as would tile together, so row 1 broke 2-up but row 2 broke
   at a different width and the columns never lined up under each other —
   read as clutter rather than a grid. Fixed tracks keep every group's badges
   left-aligned to the same two x-positions all the way down. */
.tools__groups {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: clamp(2rem, 4vw, 3.5rem);
  row-gap: clamp(1.75rem, 3vw, 2.5rem);
}

.tools__label {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 0.9rem;
}

.tools__list { display: flex; flex-wrap: wrap; gap: 0.45rem; }

.tool-badge {
  padding: 0.5rem 0.85rem;
  border-radius: 100px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  color: var(--text-2);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  transition: color 240ms ease, border-color 240ms ease, background 240ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .tool-badge:hover {
    color: var(--white);
    border-color: var(--green-35);
    background: var(--glass-bg-hover);
  }
}

/* =============================================================================
   WORK / PROOF
   ========================================================================== */
.work__group-title {
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 1.1rem;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-3);
}
.work__group-title:first-of-type { margin-top: 0; }

.work__row { display: grid; gap: clamp(0.85rem, 1.5vw, 1.15rem); }
.work__row--3 { grid-template-columns: repeat(3, 1fr); }
.work__row--shots { grid-template-columns: repeat(3, 1fr); }

.proof {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 1.35rem;
  min-height: 100%;
  border-radius: var(--radius);
  color: var(--white);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
  transition: border-color 260ms ease, box-shadow 260ms ease,
              background 260ms ease, transform 220ms var(--ease-out);
}
.proof::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: var(--glass-edge);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}

.proof__tag {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--green);
}

.proof__title {
  font-size: 1rem;
  line-height: 1.35;
  font-weight: 500;
  flex: 1;
}

.proof__link {
  margin-top: 0.35rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--green);
}
.proof__link span { display: inline-block; transition: transform 240ms var(--ease-out); }

/* Reel cards get a 9:16 frame with a play glyph, standing in for the Instagram
   thumbnails, which are not available as local assets. */
.proof__reel-frame {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-s);
  background:
    radial-gradient(70% 70% at 50% 45%, rgba(0,255,156,0.10) 0%, transparent 70%),
    repeating-linear-gradient(115deg, #111 0 12px, #141414 12px 24px);
  border: 1px solid var(--line);
  overflow: hidden;
}
.proof__play {
  width: 0; height: 0;
  border-left: 15px solid var(--green);
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  filter: drop-shadow(0 0 10px var(--green-glow));
  translate: 3px 0;
  transition: scale 260ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .proof:hover {
    border-color: var(--green-35);
    background: var(--glass-bg-hover);
    box-shadow: 0 14px 40px rgba(0, 0, 0, 0.48), 0 0 34px rgba(0, 255, 156, 0.14);
  }
  .proof:hover::after { background: var(--glass-edge-hover); }
  .proof:hover .proof__link span { transform: translateX(4px); }
  .proof:hover .proof__play { scale: 1.15; }
}

.shot {
  margin: 0;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
  transition: border-color 260ms ease, box-shadow 260ms ease;
}
.shot img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: top center;
}
.shot figcaption {
  padding: 0.7rem 1rem 0.85rem;
  color: var(--text-3);
  font-size: 0.8125rem;
}
@media (hover: hover) and (pointer: fine) {
  .shot:hover { border-color: var(--green-35); box-shadow: 0 0 32px rgba(0,255,156,0.1); }
}

.self-callout {
  margin-top: clamp(2rem, 4vw, 3rem);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border-radius: var(--radius);
  border: 1px solid var(--green-15);
  background:
    radial-gradient(110% 160% at 100% 0%, rgba(0,255,156,0.10) 0%, transparent 60%),
    var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
  text-align: center;
}
.self-callout__kicker {
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-3);
}
.self-callout__line {
  margin-top: 0.5rem;
  font-size: clamp(1.35rem, 1rem + 1.6vw, 2rem);
  font-weight: 600;
  letter-spacing: -0.03em;
}

/* =============================================================================
   CTA
   ========================================================================== */
.cta {
  position: relative;
  padding-block: clamp(5.5rem, 13vh, 9rem);
  text-align: center;
  overflow: hidden;
  isolation: isolate;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.cta__bg { position: absolute; inset: 0; z-index: -1; }
/* Bright green rays would drop white text to ~1.4:1, so the copy sits on a
   near-black ellipse while the rays outside it stay fully saturated. The
   artwork's own dark core lines up with this ellipse. */
.cta__bg::after {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(58% 62% at 50% 50%,
      rgba(10,10,10,0.95) 0%, rgba(10,10,10,0.9) 55%, rgba(10,10,10,0.2) 100%),
    linear-gradient(to right,
      var(--bg) 0%, transparent 22%, transparent 78%, var(--bg) 100%);
}
.cta__video {
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0.95;
}

.cta__title { font-size: clamp(1.9rem, 1.2rem + 2.8vw, 3.25rem); }
.cta__sub { margin: 1rem auto 2.25rem; color: var(--text-2); max-width: 34ch; }

/* =============================================================================
   FOOTER
   ========================================================================== */
.footer { padding-block: clamp(3.5rem, 7vw, 5rem) 2rem; }

.footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: clamp(2rem, 5vw, 3rem);
}

.footer__brand img { width: auto; height: 42px; }
.footer__tagline {
  margin-top: 0.6rem;
  color: var(--text-3);
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
}

.socials { display: flex; gap: clamp(1.25rem, 3vw, 2rem); }

.social { position: relative; display: flex; flex-direction: column; align-items: center; gap: 0.5rem; }

.social__link {
  position: relative;
  display: grid;
  place-items: center;
  width: 48px; height: 48px;
  border-radius: 14px;
  background: rgba(0, 255, 156, 0.07);
  border: 1px solid var(--green-15);
  color: var(--green);
  transition: transform 240ms var(--ease-out), border-color 240ms ease,
              box-shadow 240ms ease, background-color 240ms ease;
}
.social__icon svg { width: 22px; height: 22px; }

/* Glassmorphism profile card that expands out of the icon. It scales from the
   bottom (its trigger) rather than from its own centre. */
.social__card {
  position: absolute;
  bottom: calc(100% + 12px);
  left: 50%;
  width: 208px;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.85rem 0.95rem;
  border-radius: 14px;
  background: rgba(22, 24, 23, 0.82);
  border: 1px solid var(--green-35);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55), 0 0 28px rgba(0, 255, 156, 0.18);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  text-align: left;
  opacity: 0;
  transform: translate(-50%, 6px) scale(0.96);
  transform-origin: bottom center;
  pointer-events: none;
  transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out);
}
.social__card-name { color: var(--green); font-size: 0.8125rem; font-weight: 600; }
.social__card-sub  { color: var(--text-2); font-size: 0.6875rem; line-height: 1.45; }

@media (hover: hover) and (pointer: fine) {
  .social__link:hover {
    transform: translateY(-3px);
    border-color: var(--green-55);
    background: rgba(0, 255, 156, 0.13);
    box-shadow: 0 0 26px var(--green-glow);
  }
  .social__link:hover .social__card { opacity: 1; transform: translate(-50%, 0) scale(1); }
}
/* Keyboard parity: focus shows the same card hover does. */
.social__link:focus-visible .social__card { opacity: 1; transform: translate(-50%, 0) scale(1); }

/* On touch the always-visible label replaces the card entirely; leaving the
   card in the layout pushed the page horizontally at 390px. */
@media (hover: none), (pointer: coarse) {
  .social__card { display: none; }
}

/* Always-visible text label — the touch equivalent of the hover card. */
.social__label {
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* --- email reveal --------------------------------------------------------- */
/* The address is a fourth icon matching the socials; clicking it discloses the
   address rather than opening a mail client straight away. */
.social--email .social__link { cursor: pointer; }

.email-reveal {
  position: absolute;
  bottom: calc(100% + 12px);
  left: 50%;
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 0.6rem 0.55rem 0.85rem;
  border-radius: 14px;
  white-space: nowrap;
  background: rgba(22, 24, 23, 0.86);
  border: 1px solid var(--green-35);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55), 0 0 28px rgba(0, 255, 156, 0.18);
  backdrop-filter: blur(18px) saturate(180%);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  transform-origin: bottom center;
  z-index: 5;
}
.email-reveal[hidden] { display: none; }

/* animates in from the icon it belongs to */
.email-reveal[data-open] { animation: email-in 200ms var(--ease-out) both; }
@keyframes email-in {
  from { opacity: 0; transform: translateY(6px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}

.email-reveal__addr {
  font-size: 0.875rem;
  color: var(--green);
  border-bottom: 1px solid transparent;
  transition: border-color 200ms ease, color 200ms ease;
}
.email-reveal__copy {
  padding: 0.3rem 0.6rem;
  border-radius: 8px;
  border: 1px solid var(--line-2);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-2);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transition: color 200ms ease, border-color 200ms ease, background-color 200ms ease;
}
.email-reveal__copy[data-copied] { color: var(--green); border-color: var(--green-35); }

@media (hover: hover) and (pointer: fine) {
  .email-reveal__addr:hover { color: var(--green-hover); border-bottom-color: var(--green); }
  .email-reveal__copy:hover { color: var(--white); border-color: var(--green-35); }
}

/* Email is the last icon, so on narrow screens the panel opens leftward from
   its right edge instead of centring on the icon and running off-screen. */
@media (max-width: 860px) {
  .email-reveal {
    left: auto; right: 0;
    translate: 0 0;
    transform-origin: bottom right;
    max-width: calc(100vw - 2 * var(--gutter));
    white-space: normal;
  }
  .email-reveal__addr { word-break: break-all; }
}

@media (prefers-reduced-motion: reduce) {
  .email-reveal[data-open] { animation: none; }
}

.footer__copy {
  max-width: var(--maxw);
  margin: clamp(2.5rem, 5vw, 3.5rem) auto 0;
  padding: 1.5rem var(--gutter) 0;
  border-top: 1px solid var(--line);
  color: var(--text-3);
  font-size: 0.75rem;
  text-align: center;
}

/* =============================================================================
   CURSOR LIGHT-BEAM TRAIL
   One continuous stroke through a chain of eased points (quadratic-smoothed
   in JS), not discrete dots. Two paths: a wide blurred glow underneath, and a
   crisp core on top whose stroke is a gradient running tail-to-head, so the
   beam fades away behind the cursor rather than repeating in segments.
   ========================================================================== */
.cursor-trail {
  position: fixed; inset: 0;
  width: 100vw; height: 100vh;
  z-index: 400;
  pointer-events: none;
  overflow: visible;
}
.trail-glow,
.trail-core {
  stroke-linecap: round;
  stroke-linejoin: round;
  will-change: d;
}
.trail-glow {
  stroke: var(--green);
  stroke-width: 6;
  stroke-opacity: 0.14;
  filter: blur(4px);
}
.trail-core {
  stroke-width: 1.4;
}
/* Suppressed over the hero so it never competes with the reveal effect. */
.cursor-trail[data-hidden] { opacity: 0; transition: opacity 200ms ease; }

/* =============================================================================
   SCROLL REVEAL
   ========================================================================== */
[data-inview] {
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition: opacity 450ms cubic-bezier(0.16, 1, 0.3, 1), transform 450ms cubic-bezier(0.16, 1, 0.3, 1);
  will-change: opacity, transform;
}
[data-inview="in"] {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* =============================================================================
   PRICING PAGE
   Tiles reuse the .card glass shell, icon treatment, and .tags pill component
   as-is (see the .services__grid .card scoping note above) — only the tier
   rows, the AI full-width tile, and the cursor-glow below are new. The
   homepage's own price line on each service card (.card__price) lives here
   too since it is the same feature, just surfaced in two places.
   ========================================================================== */
.card__price {
  display: inline-block;
  margin-top: 0.15rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--green);
  transition: color 220ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .card__price:hover { color: var(--green-hover); }
}

.price-hero__title { max-width: 22ch; }
.price-hero__accent { color: var(--green); }

.price-hero__sub {
  color: var(--text-2);
  max-width: 52ch;
  margin-top: 0.85rem;
}

.price-hero__note {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8125rem;
  color: var(--text-3);
  margin-top: 0.5rem;
}

.price-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2vw, 1.5rem);
  margin-top: clamp(2.5rem, 5vw, 4rem);
}

.price-tier {
  padding-block: 0.8rem;
  border-top: 1px solid var(--line);
}
.price-tier:first-of-type { margin-top: 0.2rem; }
.price-tier__top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
  margin-bottom: 0.2rem;
}
.price-tier__name { font-size: 0.84375rem; font-weight: 600; }
.price-tier__price {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8125rem;
  color: var(--green);
  white-space: nowrap;
}
.price-tier__desc { font-size: 0.8125rem; color: var(--text-2); line-height: 1.5; }

.price-tile__cta { margin-top: 1.35rem; align-self: flex-start; }

/* Agentic AI — the one contact-only, full-width tile */
.price-tile--ai {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  background: linear-gradient(135deg, var(--green-8), rgba(255, 255, 255, 0.03));
  border-color: var(--green-35);
}
.price-tile--ai .card__icon { margin-bottom: 0; flex-shrink: 0; }
.price-tile--ai__copy { flex: 1; }
.price-tile--ai__copy .card__title { font-size: 1.25rem; margin-bottom: 0.3rem; }
.price-tile--ai__copy p { color: var(--text-2); font-size: 0.875rem; max-width: 480px; }
.price-tile--ai .price-tile__cta { margin-top: 0; flex-shrink: 0; }

.price-footnote {
  margin-top: clamp(2rem, 4vw, 3rem);
  font-size: 0.8125rem;
  color: var(--text-3);
  max-width: 68ch;
  line-height: 1.6;
}
.price-footnote strong { color: var(--text-2); }

.price-cta {
  margin-top: clamp(3rem, 6vw, 4.5rem);
  padding: clamp(2rem, 4vw, 2.75rem);
  border-radius: var(--radius);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  text-align: center;
}
.price-cta__title { font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2rem); }
.price-cta__sub { margin: 0.6rem auto 1.75rem; color: var(--text-2); max-width: 40ch; }

/* Cursor-follow glow, present only on this page. transform stays a static
   centring offset; JS drives left/top only, so the two never fight over the
   same property — same trick .rotate/.transform use elsewhere in this file. */
#price-glow {
  position: fixed;
  left: 0; top: 0;
  width: 420px; height: 420px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, var(--green-glow) 0%, transparent 70%);
  filter: blur(40px);
  opacity: 0.22;
  pointer-events: none;
  z-index: 1;
}

/* =============================================================================
   RESPONSIVE — mobile and tablet are laid out for their own shape, not scaled
   down from desktop.
   ========================================================================== */

/* ---- tablet -------------------------------------------------------------- */
@media (max-width: 1000px) {
  .services__grid { grid-template-columns: repeat(12, 1fr); }
  .card-slot[data-row="1"] { grid-column: span 6; }
  .card-slot[data-row="2"] { grid-column: span 6; }
  /* 7 cards over 2 columns leaves a widow; the last one runs full width. */
  .card-slot:last-child { grid-column: span 12; }

  .work__row--3, .work__row--shots { grid-template-columns: repeat(2, 1fr); }
  .work__row--3 > :last-child { grid-column: span 2; }

  .process__grid { grid-template-columns: repeat(2, 1fr); }

  .price-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ---- mobile -------------------------------------------------------------- */
@media (max-width: 860px) {
  :root { --radius: 14px; }

  /* The nav is the same button-and-panel at every width; on a narrow screen
     the panel just must not exceed the viewport. */
  .nav__menu { min-width: 0; width: min(19rem, calc(100vw - 2 * var(--gutter))); }

  /* --- hero: the robot moves to the top half and the copy sits under it,
         full width. Overlaying the headline on it does not work at 390px. --- */
  .hero {
    min-height: auto;
    align-items: flex-start;
    flex-direction: column;
    justify-content: flex-end;
    padding-top: var(--nav-h);
    padding-bottom: clamp(2.5rem, 7vh, 4rem);
  }
  .hero__media {
    position: relative;
    width: calc(100% + (2 * var(--gutter)));
    margin-inline: calc(-1 * var(--gutter));
    height: min(62svh, 460px);
    z-index: -2;
  }
  .hero__scrim {
    background:
      linear-gradient(to top, var(--bg) 0%, rgba(10,10,10,0.55) 26%, transparent 62%),
      linear-gradient(to bottom, rgba(10,10,10,0.55) 0%, transparent 30%);
  }
  /* No negative pull-up here any more. That existed to tuck the copy under the
     portrait, whose base dissolved into the scrim; the robot has solid feet, so
     overlapping it just puts text on top of boots. */
  .hero__content { max-width: none; }
  .hero__title { font-size: clamp(2.75rem, 12vw, 4rem); }
  .hero__cta { margin-top: 1.5rem; }
  .hero__cta .btn { flex: 1 1 auto; }

  /* --- about: stack, portrait above the copy --- */
  .about__grid { gap: 1.75rem; }

  /* --- timeline: three columns is unreadable at this width, so the rail turns
         vertical and the copy sits beside each node, left-aligned --- */
  .timeline {
    grid-template-columns: 1fr;
    gap: 1.75rem;
    padding-top: 0;
    padding-left: 1.5rem;
  }
  .timeline::before {
    top: 6px; bottom: 6px;
    left: 4px; right: auto;
    width: 1px; height: auto;
    background: linear-gradient(to bottom,
      transparent 0%, var(--line-2) 10%, var(--line-2) 90%, transparent 100%);
  }
  .timeline__item::before { top: 6px; left: -1.5rem; translate: 0 0; }
  .timeline__title,
  .timeline__text { text-align: left; }

  /* --- services: single column, icon inline with the title so cards stay
         short enough to scan by scrolling --- */
  .services__grid { grid-template-columns: 1fr; }
  .card-slot[data-row="1"],
  .card-slot[data-row="2"],
  .card-slot:last-child { grid-column: 1 / -1; }
  /* scoped to the homepage bento grid only — the pricing page reuses .card's
     glass shell but keeps its own flex-column layout at every width, since it
     has no .card__desc to anchor this icon+title/desc/tags area map */
  .services__grid .card {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
      'icon title'
      'desc desc'
      'tags tags';
    column-gap: 0.9rem;
    row-gap: 0.55rem;
    align-items: center;
  }
  .card__icon  { grid-area: icon; margin-bottom: 0; }
  .card__title { grid-area: title; font-size: 1.125rem; }
  .card__desc  { grid-area: desc; }
  .tags        { grid-area: tags; }

  /* --- how i work: one step at a time --- */
  .process__grid { grid-template-columns: 1fr; }

  /* --- tools --- */
  .tools__groups { grid-template-columns: 1fr; }

  /* --- work --- */
  .work__row--3, .work__row--shots { grid-template-columns: 1fr; }
  .work__row--3 > :last-child { grid-column: auto; }

  /* --- footer --- */
  .footer__inner { flex-direction: column; align-items: center; text-align: center; }
  .socials { gap: 1.75rem; }

  /* --- pricing --- */
  .price-grid { grid-template-columns: 1fr; }
  .price-tile--ai { flex-direction: column; align-items: flex-start; }
}

@media (max-width: 420px) {
  .tags li { font-size: 0.65rem; }
  .hero__cta { flex-direction: column; align-items: stretch; }
}

/* =============================================================================
   REDUCED MOTION
   Movement is removed; opacity and colour transitions that aid comprehension
   are kept, per WCAG guidance.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .cursor-trail { display: none; }
  #price-glow { display: none; }

  [data-inview] { opacity: 1; transform: none; }

  .about__lead .c { transform: none !important; }

}

/* Touch devices have no cursor to trail. */
@media (hover: none), (pointer: coarse) {
  .cursor-trail { display: none; }
  #price-glow { display: none; }
}
