/* ==========================================================================
   TalkXO — design tokens
   ========================================================================== */
:root {
  --bg: #ffffff;
  --bg-deep: #eae6f6;
  --ink: #1a1d21;
  --ink-soft: #4f4f4f;
  --purple: #5a4f73;
  --purple-deep: #423a5c;
  --blue: #4a7fc4;
  --mint: #a1e4b2;
  --peach: #ffc896;
  --white: #ffffff;
  --line: rgba(26, 29, 33, 0.08);
  --line-strong: rgba(26, 29, 33, 0.14);
  --shadow-soft: 0 20px 60px -30px rgba(26, 29, 33, 0.35);
  --shadow-lift: 0 30px 80px -30px rgba(90, 79, 115, 0.45);

  --font-display: "DM Sans", -apple-system, "Segoe UI", sans-serif;
  --font-grotesk: "Host Grotesk", -apple-system, "Segoe UI", sans-serif;
  --font-serif: "Crimson Pro", Georgia, serif;
  --font-script: "Gochi Hand", cursive;

  --container: 1180px;
  --radius-lg: 28px;
  --radius-md: 18px;
  --radius-sm: 12px;
  --radius-pill: 999px;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ==========================================================================
   Reset
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
/* iOS Safari ties horizontal page-scroll to the <html> element specifically —
   overflow-x:hidden on body alone (below) doesn't stop it there, which is
   why a few px of overflow (marquee, off-canvas decorative elements) shows
   up as a scrollable grey gutter on real iPhones even though desktop Chrome
   never surfaces it */
html { scroll-behavior: smooth; overflow-x: hidden; }
@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; }
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  /* NOT overflow-x:hidden here — html already clips horizontal overflow above.
     Setting a non-visible overflow-x on body too forces its overflow-y to
     compute as auto (CSS overflow pairing rule), which turns body into its
     own scroll container that never actually receives scroll deltas —
     any position:sticky descendant then "sticks" relative to a box that
     never moves, i.e. behaves like normal flow. This is why the services
     page mascot rail wasn't sticking. */
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }
h1, h2, h3, h4, h5, h6, p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 clamp(20px, 5vw, 32px);
}
section { position: relative; }

/* ==========================================================================
   Background mesh
   ========================================================================== */
.mesh-bg {
  position: fixed;
  inset: 0;
  z-index: -2;
  background: var(--bg);
}
.blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.55;
  will-change: transform;
}
.blob--mint { width: 46vw; height: 46vw; max-width: 620px; max-height: 620px; top: -8vw; right: -10vw; background: radial-gradient(circle at 30% 30%, var(--mint), transparent 70%); animation: drift1 22s ease-in-out infinite; }
.blob--peach { width: 38vw; height: 38vw; max-width: 520px; max-height: 520px; top: 30vh; left: -14vw; background: radial-gradient(circle at 60% 40%, var(--peach), transparent 70%); animation: drift2 26s ease-in-out infinite; }
.blob--violet { width: 40vw; height: 40vw; max-width: 560px; max-height: 560px; bottom: -10vh; right: -8vw; background: radial-gradient(circle at 50% 50%, #c9bdf0, transparent 70%); animation: drift3 30s ease-in-out infinite; }

@keyframes drift1 { 0%,100% { transform: translate(0,0) scale(1);} 50% { transform: translate(-4%, 6%) scale(1.08);} }
@keyframes drift2 { 0%,100% { transform: translate(0,0) scale(1);} 50% { transform: translate(6%, -4%) scale(0.94);} }
@keyframes drift3 { 0%,100% { transform: translate(0,0) scale(1);} 50% { transform: translate(-5%, -5%) scale(1.06);} }

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 24px;
  border-radius: var(--radius-pill);
  font-size: 15px;
  font-weight: 500;
  border: 1px solid transparent;
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease), background 0.35s var(--ease), color 0.35s var(--ease);
}
.btn svg { transition: transform 0.35s var(--ease); }
.btn:hover svg { transform: translate(3px, -3px); }
.btn--dark {
  background: var(--ink);
  color: var(--white);
  box-shadow: 0 14px 30px -14px rgba(26, 29, 33, 0.55);
}
.btn--dark:hover { transform: translateY(-2px); box-shadow: 0 20px 40px -14px rgba(26, 29, 33, 0.6); }
.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--line-strong);
}
.btn--ghost:hover { background: var(--white); border-color: transparent; box-shadow: var(--shadow-soft); transform: translateY(-2px); }
.btn--light {
  background: var(--white);
  color: var(--ink);
}
.btn--light:hover { transform: translateY(-2px); box-shadow: var(--shadow-soft); }
.btn--sm { padding: 11px 18px; font-size: 13.5px; }

/* ==========================================================================
   Nav
   ========================================================================== */
.nav-wrap {
  position: sticky; top: clamp(12px, 2vw, 20px); z-index: 100;
  /* floating pill, not an edge-to-edge bar: inset from both sides and the
     top, rounded all the way round instead of just a bottom divider.
     A percentage/vw-based margin barely reads as "floating" on a wide
     screen (32px of gap on a 2000px monitor is invisible) — cap the bar's
     own width instead, so the gap actually grows on wide viewports. */
  width: calc(100% - clamp(32px, 8vw, 64px));
  max-width: 1100px;
  margin: 0 auto;
  border-radius: 44px;
  background: rgba(255, 255, 255, 0.6);
  /* saturate() amplifies whatever colour sits behind the glass — the decorative mesh
     blobs included, which is what was tinting the bar. Keep blur, drop the boost.
     A feTurbulence->feDisplacementMap SVG filter was tried here for real glass
     refraction; verified it silently no-ops in every engine tested (even at
     extreme diagnostic values), so it's been dropped rather than shipped as
     dead weight — blur(18px) is the only thing actually doing the "glass" work. */
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(24px);
  /* the border is what sells "glass" — a light edge catching light, not a flat divider line.
     Liquid-glass rim: brighter top highlight (light hitting the edge), the outer shadow
     is wide/soft/faint instead of tight and dark — a bar of glass sitting a little above
     the page, not a hard-edged panel dropped onto it. Full border now (floating card,
     not a full-width bar), not just a bottom divider. */
  border: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow: none;
  overflow: hidden;
  transition: box-shadow 0.4s var(--ease), background 0.4s var(--ease);
}
/* The SVG-filter refraction tried above (feDisplacementMap) had real cross-browser
   support gaps — verified it silently no-ops in testing even at extreme values,
   which is why it's gone. These three layers are what actually renders the "glass"
   look everywhere, since none of
   them depend on backdrop-filter at all: a static noise-grain texture (real glass has
   visible surface imperfection), a soft specular highlight (light catching the top-left
   like a curved edge), and a faint prismatic tint on the bottom edge. Left off
   .nav-wrap--overlay's unscrolled state on purpose — it's meant to be fully invisible
   over the hero photo, not textured. */
.nav-wrap:not(.nav-wrap--overlay)::before,
.nav-wrap--overlay.is-scrolled::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    radial-gradient(120% 140% at 12% 0%, rgba(255, 255, 255, 0.55), transparent 55%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.02 0'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: no-repeat, repeat;
  mix-blend-mode: overlay;
}
.nav-wrap:not(.nav-wrap--overlay)::after,
.nav-wrap--overlay.is-scrolled::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; z-index: 1; pointer-events: none;
  background: linear-gradient(90deg,
    rgba(255, 200, 210, 0.5) 0%, rgba(255, 240, 200, 0.4) 25%,
    rgba(200, 240, 220, 0.4) 50%, rgba(200, 220, 255, 0.45) 75%,
    rgba(230, 200, 255, 0.4) 100%);
}
.nav .nav-links, .nav .logo-link, .nav .nav-toggle { position: relative; z-index: 1; }
/* homepage only: floats fully transparent over the hero photo until scrolled,
   then fades into the same glass treatment every other page has by default */
.nav-wrap--overlay {
  position: fixed; left: 0; right: 0;
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.nav-wrap--overlay .nav-links a { color: rgba(255, 255, 255, 0.92); }
.nav-wrap--overlay .nav-links a:hover,
.nav-wrap--overlay .nav-links a[aria-current="page"] { background: rgba(255, 255, 255, 0.16); color: var(--white); }
.nav-wrap--overlay .nav-toggle { background: rgba(255, 255, 255, 0.16); }
.nav-wrap--overlay .nav-toggle span,
.nav-wrap--overlay .nav-toggle span::before,
.nav-wrap--overlay .nav-toggle span::after { background: var(--white); }
.nav-wrap--overlay.is-scrolled {
  background: rgba(255, 255, 255, 0.8);
  border-color: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(24px);
  box-shadow: none;
}
.nav-wrap--overlay.is-scrolled .nav-links a { color: var(--ink-soft); }
.nav-wrap--overlay.is-scrolled .nav-links a:hover,
.nav-wrap--overlay.is-scrolled .nav-links a[aria-current="page"] { background: var(--bg); color: var(--ink); }
.nav-wrap--overlay.is-scrolled .nav-toggle { background: var(--bg); }
.nav-wrap--overlay.is-scrolled .nav-toggle span,
.nav-wrap--overlay.is-scrolled .nav-toggle span::before,
.nav-wrap--overlay.is-scrolled .nav-toggle span::after { background: var(--ink); }

.nav-wrap.is-scrolled {
  background: rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(24px);
  box-shadow: none;
}
.nav {
  max-width: var(--container);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px clamp(20px, 5vw, 32px);
}

.logo-link { display: inline-flex; align-items: center; transition: opacity 0.3s var(--ease); }
.logo-link:hover { opacity: 0.75; }
.logo-img { height: 50px; width: auto; display: block; }
.footer-logo-link .logo-img { height: 26px; }

.nav-links { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.nav-links a {
  display: inline-flex;
  align-items: center;
  line-height: 1;
  padding: 9px 16px;
  border-radius: var(--radius-pill);
  font-size: 14.5px;
  font-weight: 500;
  color: var(--ink-soft);
  transition: background 0.3s var(--ease), color 0.3s var(--ease);
}
.nav-links a:hover { background: var(--bg); color: var(--ink); }
.nav-links a[aria-current="page"] { background: var(--bg); color: var(--ink); font-weight: 600; }
.nav-toggle {
  display: none;
  width: 40px; height: 40px;
  border-radius: 50%;
  border: none;
  background: var(--bg);
  align-items: center;
  justify-content: center;
}
.nav-toggle span, .nav-toggle span::before, .nav-toggle span::after {
  content: ""; display: block; width: 16px; height: 2px; background: var(--ink); position: relative; transition: transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
.nav-toggle span::before { position: absolute; top: -5px; }
.nav-toggle span::after { position: absolute; top: 5px; }
.nav-toggle.is-open span { background: transparent; }
.nav-toggle.is-open span::before { transform: rotate(45deg) translate(3.5px, 3.5px); }
.nav-toggle.is-open span::after { transform: rotate(-45deg) translate(3.5px, -3.5px); }

.mobile-menu {
  display: none;
  max-width: var(--container);
  margin: 10px auto 0;
  padding: 14px;
  background: var(--white);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  flex-direction: column;
  gap: 4px;
}
.mobile-menu a { padding: 12px 14px; border-radius: var(--radius-sm); font-size: 15px; }
.mobile-menu a:hover { background: var(--bg); }
.mobile-menu.is-open { display: flex; }

/* ==========================================================================
   Opening — manifesto sequence
   ========================================================================== */
.opening { position: relative; }
.opening-beat {
  display: flex; align-items: center; justify-content: center; text-align: center;
  min-height: 76vh; padding: 60px 0;
}
.opening-beat--2 { min-height: 54vh; }

.scroll-cue {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 8px;
  margin: 10px auto 0; padding-bottom: clamp(20px, 4vw, 40px);
  font-size: 12px; color: var(--ink-soft); letter-spacing: 0.06em; text-transform: uppercase;
  transition: color 0.3s var(--ease);
}
.scroll-cue:hover { color: var(--purple); }
.scroll-cue span {
  width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--line-strong);
  display: flex; align-items: center; justify-content: center;
  animation: bob 2.2s ease-in-out infinite;
}
.scroll-cue span::before {
  content: ""; width: 6px; height: 6px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
}
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(5px); } }

.eyebrow-pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 16px; border-radius: var(--radius-pill);
  background: var(--white); border: 1px solid var(--line);
  font-size: 13px; font-weight: 500; color: var(--purple);
  box-shadow: var(--shadow-soft);
  margin-bottom: 28px;
}
.eyebrow-pill .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--mint); box-shadow: 0 0 0 4px rgba(161,228,178,0.35); }

h1 .script, .opening-beat .script, .hero-fold .script {
  font-family: var(--font-script);
  font-weight: 400;
  font-style: normal;
  font-size: 1.14em;
  color: var(--purple);
  padding: 0 0.06em;
  display: inline-block;
}

.cta-row { margin-top: 34px; display: flex; justify-content: center; gap: 14px; flex-wrap: wrap; }

.opening-line {
  margin: 0 auto;
  max-width: 26ch;
  font-size: clamp(26px, 4.6vw, 48px);
  line-height: 1.32;
  font-weight: 400;
  letter-spacing: -0.015em;
}
.opening-line .word { color: var(--line-strong); transition: color 0.5s var(--ease); }
.opening-line .word.is-lit { color: var(--ink); }
.opening-line .accent .word.is-lit { color: var(--purple); font-weight: 600; }

/* ==========================================================================
   Hero fold — sky photo
   ========================================================================== */
.hero-fold {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
  color: var(--white);
  background: #4a7fc4;
  -webkit-user-select: none;
  user-select: none;
}
.hero-sky { position: absolute; inset: 0; z-index: 0; overflow: hidden; perspective: 1000px; background: #4a7fc4; }
.hero-sky-img {
  width: 100%; height: 100%; object-fit: cover; object-position: center 58%;
  transform-style: preserve-3d; will-change: transform;
}
.hero-sky::after {
  content: "";
  position: absolute; inset: 0;
  /* soft vignette up top for text contrast, then a long, gradual blend into the page bg well before the edge — no hard seam */
  background: linear-gradient(180deg,
    rgba(10, 20, 45, 0.25) 0%,
    rgba(10, 20, 45, 0.04) 16%,
    rgba(10, 20, 45, 0) 32%,
    rgba(255, 255, 255, 0) 62%,
    rgba(255, 255, 255, 1) 90%,
    rgba(255, 255, 255, 1) 100%
  );
}
.hero-fold-inner {
  position: relative; z-index: 2; text-align: center;
  /* nav is now a fixed overlay (not sticky-in-flow), so hero-fold already spans
     the true full viewport and centers correctly on its own — no compensation
     margin needed here anymore. */
  /* top/bottom only — left/right padding comes from the shared .container class;
     a padding shorthand here would zero those out since it's the same property */
  padding-top: clamp(40px, 7vw, 80px);
  padding-bottom: clamp(60px, 10vw, 110px);
}

@media (max-width: 640px) {
  /* back to real centering (min-height + flex) — the earlier padding-only
     approach traded away centering entirely and just pinned everything to
     the top with a fixed gap, which looked worse, not better. Content is
     now trimmed (smaller type, tighter line-height, natural text wrap) so it
     comes close to fitting one screen; if it's still a little taller than
     that on a given device, that's fine — the sky keeps going and fades to
     white further down, same as desktop, and the buttons are one small
     scroll away rather than forced to cram into exactly one screen */
  .hero-fold { min-height: 100vh; min-height: 100svh; display: flex; align-items: center; }
  .hero-fold-inner { padding-top: 96px; padding-bottom: 56px; }
  .hero-fold h1 { font-size: 28px; }
  /* the <br> tags give a specific line-break rhythm tuned for wide desktop
     lines — at mobile width they force awkward breaks ("through" stranded
     from "your"); switching them off lets the browser wrap the whole
     sentence naturally against the actual available width instead */
  .hero-fold h1 br { display: none; }
  .hero-fold-sub { font-size: 15px; line-height: 1.45; }
  .cta-row { flex-direction: column; width: 100%; max-width: 320px; margin-left: auto; margin-right: auto; }
  .cta-row .btn { width: 100%; justify-content: center; }
  /* left side of the source photo has more visible cloud detail than the
     centred crop was showing */
  .hero-sky-img { object-position: left 58%; }
  /* content is taller on mobile now (stacked buttons etc.), so it sits
     closer to where the sky fades to white than on desktop — push that
     transition further down so blue/sky stays visible longer instead of
     hitting flat white right behind the buttons */
  .hero-sky::after {
    /* the left crop shows more cloud, and clouds are bright enough to wash
       out the subhead text once the dark vignette above has already faded
       to nothing by 32% — extend a gentle darkening through the text zone
       instead of a hard early cutoff, so it stays legible over cloud or sky */
    background: linear-gradient(180deg,
      rgba(10, 20, 45, 0.3) 0%,
      rgba(10, 20, 45, 0.14) 20%,
      rgba(10, 20, 45, 0.16) 45%,
      rgba(10, 20, 45, 0.04) 65%,
      rgba(255, 255, 255, 0) 78%,
      rgba(255, 255, 255, 1) 97%,
      rgba(255, 255, 255, 1) 100%
    );
  }
}

.hero-fold h1 {
  font-family: var(--font-grotesk);
  font-weight: 500;
  font-size: clamp(32px, 5vw, 64px);
  letter-spacing: -0.03em;
  line-height: 1.1;
  max-width: 32ch;
  margin: 0 auto;
  color: var(--white);
}
.hero-fold h1 b { font-weight: 600; }
.hero-light-line { font-weight: 300; }
.hero-fold .script { color: var(--purple); }
.fx-hover-target { cursor: none; }
.hero-fx-lottie-float {
  position: fixed;
  top: 0; left: 0;
  width: 190px; height: 190px;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.7) scaleX(-1);
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
  z-index: 200;
  filter: drop-shadow(0 16px 30px rgba(10, 20, 45, 0.35));
}
.hero-fx-lottie-float.is-active {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1) scaleX(-1);
}

/* inline phrase hover effects — the copy acting out its own words */
.fx-cut, .fx-sharpen {
  position: relative;
  display: inline-block;
  transition: transform 0.25s var(--ease), letter-spacing 0.3s var(--ease);
}
.fx-cut {
  cursor: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28"><text x="14" y="21" font-size="22" text-anchor="middle" transform="rotate(-90 14 14)">%E2%9C%82%EF%B8%8F</text></svg>') 14 14, pointer;
}
.fx-cut::after {
  content: "";
  position: absolute; left: 0; right: 100%; top: 54%;
  height: 3px; margin-top: -1.5px;
  background: currentColor;
  border-radius: 2px;
  transition: right 0.5s var(--ease);
  pointer-events: none;
}
.fx-cut:hover::after { right: 0; }
.fx-cut:hover { animation: fxSnip 0.4s var(--ease); }
@keyframes fxSnip {
  0%, 100% { transform: rotate(0deg); }
  35% { transform: rotate(-2deg) translateY(1px); }
  65% { transform: rotate(1.5deg); }
}

.fx-sharpen {
  cursor: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28"><text x="14" y="22" font-size="22" text-anchor="middle">%F0%9F%98%8E</text></svg>') 14 14, pointer;
}
.fx-sharpen:hover {
  letter-spacing: -0.06em;
  transform: scale(1.03);
  text-shadow: 0 0 18px rgba(255, 255, 255, 0.55);
}

.fx-zap {
  position: relative;
  display: inline-block;
}
.fx-zap::before {
  content: "⚡";
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(0);
  font-size: 1.5em;
  opacity: 0;
  pointer-events: none;
  transition: transform 0.35s var(--ease), opacity 0.35s var(--ease);
  filter: drop-shadow(0 0 10px rgba(255, 224, 102, 0.9));
}
.fx-zap:hover::before {
  transform: translate(-50%, -50%) scale(1.6);
  opacity: 0.95;
}
.fx-zap:hover {
  animation: fxZap 0.3s var(--ease);
  text-shadow: 0 0 16px rgba(255, 224, 102, 0.85);
}
@keyframes fxZap {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-2px); }
  50% { transform: translateX(2px); }
  75% { transform: translateX(-1px); }
}
.hero-fold-sub {
  font-family: var(--font-grotesk);
  font-weight: 400;
  margin: 24px auto 0;
  max-width: 46ch;
  font-size: clamp(17px, 2.1vw, 21px);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.85);
}
.hero-fold-sub b { font-weight: 600; color: #fff; }
.hero-fold .cta-row { margin-top: 32px; }
/* liquid-glass treatment — the plain outline read as nearly invisible
   against the sky photo wherever it happened to sit. True Apple-style
   refraction only renders via backdrop-filter:url(#svg-filter), which is
   Chromium-only and falls back to a flat blur on Safari/iOS — since this
   button lives on a page tested heavily on iPhone, a CSS-only layered
   approximation (blur + saturation, a specular rim highlight, a diagonal
   sheen) is the one that actually looks the same everywhere. */
.btn--outline-light {
  position: relative; overflow: hidden;
  /* no colour fill — saturate() was amplifying the blue sky behind it,
     which read as a blue fill even though no blue was ever specified.
     Blur only, kept neutral/frosted like the glass itself, not a tint. */
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  color: var(--white);
  border-color: rgba(255, 255, 255, 0.4);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.55),
    inset 0 -1px 1px rgba(255, 255, 255, 0.06),
    0 8px 24px -14px rgba(10, 20, 45, 0.4);
  /* the glass stays honest to whatever's behind it (bright cloud included),
     so white text alone can wash out there — a dark edge + soft glow keeps
     it legible without darkening the glass itself */
  text-shadow: 0 1px 2px rgba(10, 20, 45, 0.55), 0 0 10px rgba(10, 20, 45, 0.3);
}
.btn--outline-light::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(115deg, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.08) 32%, rgba(255, 255, 255, 0) 55%);
  pointer-events: none;
}
.btn--outline-light:hover {
  background: rgba(255, 255, 255, 0.22); border-color: rgba(255, 255, 255, 0.65); transform: translateY(-2px);
}


/* ==========================================================================
   Marquee
   ========================================================================== */
.marquee-section { padding: 56px 0; }
.marquee { overflow: hidden; mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent); }
.marquee-track { display: flex; align-items: center; width: max-content; gap: 0; animation: scrollX 80s linear infinite; }
.marquee-item { display: flex; align-items: center; justify-content: center; padding: 0 clamp(48px, 7vw, 130px); white-space: nowrap; }
.marquee-item img {
  height: 68px;
  width: auto;
  max-width: 280px;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.55;
  transition: opacity 0.3s var(--ease);
}
.marquee-item img:hover { opacity: 0.9; }
/* six repeats (not two) — with larger logos, one set needs to stay wider than
   the viewport even on large monitors, or the "seamless" loop shows a
   trailing gap before it restarts. Distance matches rep count: -1/6 = -16.667%. */
@keyframes scrollX { from { transform: translateX(0); } to { transform: translateX(-16.6667%); } }

/* ==========================================================================
   Section heads
   ========================================================================== */
.section-head { text-align: center; max-width: 640px; margin: 0 auto 32px; }
.eyebrow {
  font-size: 13px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--purple); margin-bottom: 14px; display: block;
}
.section-head h2 {
  font-family: var(--font-grotesk);
  font-weight: 300; font-size: clamp(30px, 4.4vw, 48px); letter-spacing: -0.03em; line-height: 1.12;
}
.section-head h2 b { font-weight: 600; }
.section-head p { margin-top: 14px; color: var(--ink-soft); font-size: 16px; line-height: 1.6; }

/* ==========================================================================
   Pillars (PRESENCE / PIPELINE / PERFORMANCE)
   ========================================================================== */
/* ==========================================================================
   Capabilities — four columns, one expands on click. Positioned via JS-set
   px left/width (not flex-grow — animating flex-grow is unreliable across
   engines; plain left/width transitions are not).
   ========================================================================== */
.capabilities { padding: clamp(60px, 10vw, 120px) 0; }
.cap-stack {
  position: relative;
  margin-top: clamp(30px, 5vw, 56px);
  height: clamp(400px, 46vw, 540px);
}
.cap-box {
  position: absolute;
  top: 0;
  height: 100%;
  border-radius: 22px;
  border: none;
  padding: 0;
  cursor: pointer;
  overflow: hidden;
  text-align: left;
  font: inherit;
  color: var(--ink);
  transition: left 0.65s cubic-bezier(0.16, 1, 0.3, 1), width 0.65s cubic-bezier(0.16, 1, 0.3, 1);
}

.cap-box--0 {
  background:
    linear-gradient(160deg, rgba(238, 249, 241, 0.68), rgba(215, 240, 223, 0.68)),
    url("assets/cap-consulting.jpg") center/cover;
}
.cap-box--1 {
  background:
    linear-gradient(160deg, rgba(255, 244, 233, 0.68), rgba(255, 224, 193, 0.68)),
    url("assets/cap-marketing.jpg") center/cover;
}
.cap-box--2 {
  background:
    linear-gradient(160deg, rgba(242, 238, 251, 0.68), rgba(225, 215, 246, 0.68)),
    url("assets/cap-automation.jpg") center/cover;
}
.cap-box--3 {
  background:
    linear-gradient(155deg, rgba(26, 29, 33, 0.78), rgba(45, 39, 69, 0.72) 60%, rgba(66, 58, 92, 0.72)),
    url("assets/cap-software.jpg") center/cover;
  color: var(--white);
}
/* subtle grain texture, uniform across all four — adds tactile depth without
   becoming a literal photo; works over both light and dark card backgrounds */
.cap-box::after {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.05;
  mix-blend-mode: overlay;
  pointer-events: none;
}

.cap-box-label, .cap-box-body {
  position: absolute; inset: 0;
  transition: opacity 0.35s var(--ease);
}
.cap-box-label {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 26px 0;
}
.cap-box.is-active .cap-box-label { opacity: 0; pointer-events: none; }
.cap-box-title {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--font-grotesk);
  font-weight: 500;
  font-size: 15px;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.cap-box-label .cap-box-num {
  font-family: var(--font-grotesk);
  font-weight: 700;
  font-size: 13px;
  opacity: 0.5;
  letter-spacing: 0.02em;
}

.cap-box-body {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: clamp(24px, 3.2vw, 44px);
  opacity: 0;
  transform: translateY(10px);
  /* fade OUT fast with no delay — the card is about to narrow and reflow this
     text, so it needs to be gone before that's visible, not lingering through it */
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease);
  pointer-events: none;
  white-space: normal;
}
.cap-box.is-active .cap-box-body {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
  /* fade IN slower, after a delay — give the card time to widen first so the
     text isn't revealed mid-reflow */
  transition: opacity 0.4s var(--ease) 0.28s, transform 0.4s var(--ease) 0.28s;
}
.cap-box-body .cap-box-num {
  font-family: var(--font-grotesk);
  font-weight: 700;
  font-size: 13px;
  opacity: 0.55;
  margin-bottom: 10px;
}
.cap-box-body h3 {
  font-family: var(--font-grotesk);
  font-weight: 500;
  font-size: clamp(24px, 3vw, 34px);
  letter-spacing: -0.01em;
  margin-bottom: 14px;
}
.cap-box-body p { font-size: 16px; line-height: 1.65; max-width: 42ch; opacity: 0.85; }

@media (max-width: 780px) {
  .cap-stack { height: auto; }
  .cap-box {
    position: relative !important; left: auto !important; width: 100% !important;
    height: 64px; margin-bottom: 10px; transition: height 0.5s var(--ease);
  }
  .cap-box.is-active { height: 260px; }
  .cap-box-label { flex-direction: row; justify-content: flex-start; align-items: center; gap: 14px; padding: 0 22px; }
  .cap-box-title { writing-mode: horizontal-tb; transform: none; font-size: 17px; }
  .cap-box-body { padding: 20px 22px; }
}

/* ==========================================================================
   Stats
   ========================================================================== */
.stats-section { padding: clamp(50px, 8vw, 90px) 0; }
.stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--line); border-radius: var(--radius-lg); overflow: hidden; border: 1px solid var(--line); }
.stats-banner { grid-column: 1 / -1; background: var(--bg); padding: clamp(28px, 4vw, 40px) 30px; text-align: center; }
.stats-banner p { font-size: clamp(16px, 2.2vw, 20px); color: var(--ink-soft); line-height: 1.5; }
.stats-banner strong { color: var(--ink); font-weight: 600; }
.stat-card { background: var(--bg); padding: 40px 30px; text-align: center; }
.stat-card .label { font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: #4a7fc4; }
.stat-card .num { font-family: var(--font-grotesk); font-weight: 500; font-size: clamp(38px, 5vw, 56px); margin-top: 14px; letter-spacing: -0.02em; }
.stat-card .sub { margin-top: 10px; font-size: 14px; color: var(--ink-soft); line-height: 1.55; }

/* ==========================================================================
   Work — bento (case studies + AI tools, mixed, no filters — reads as one set)
   ========================================================================== */
.work-section { padding: clamp(60px, 10vw, 120px) 0; background: var(--bg); position: relative; z-index: 1; }

.bento-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  /* fixed row unit, not auto — every card's span is a whole-number multiple of
     this, so heights are always predictable and never fight a neighbour's
     content for row height (that mismatch was the root of every earlier bug) */
  grid-auto-rows: 270px;
  grid-auto-flow: dense;
  gap: 18px;
}
.work-more { display: flex; justify-content: center; margin-top: clamp(36px, 6vw, 56px); }
.bento-card {
  position: relative;
  grid-column: span 2;
  border-radius: var(--radius-lg);
  padding: 30px;
  display: flex; flex-direction: column;
  background: var(--white);
  border: 1px solid var(--line);
  overflow: hidden;
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease), border-color 0.45s var(--ease);
}
.bento-card:hover { transform: translateY(-4px); border-color: rgba(74, 127, 196, 0.4); }

.bento--wide { grid-column: span 2; }
.bento--hero { grid-column: span 3; }
.bento--hero.bento-card--tool-img img { object-position: center; }
.bento--tall { grid-row: span 2; }
.bento--solo { grid-column: span 1; }

.bento-card h3 { font-size: clamp(18px, 2.1vw, 22px); font-weight: 600; letter-spacing: -0.01em; line-height: 1.35; margin-bottom: 12px; }
.bento--tall h3, .bento--hero h3 { font-size: clamp(21px, 2.6vw, 27px); }
.bento-card p { font-size: 14.5px; color: var(--ink-soft); line-height: 1.65; margin-bottom: 6px; }
.bento-link { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; font-size: 14px; margin-top: auto; padding-top: 14px; text-decoration: underline; text-underline-offset: 5px; }
.bento-link svg { transition: transform 0.35s var(--ease); }
.bento-card:hover .bento-link svg,
.bento-link:hover svg { transform: translate(3px, -3px); }

/* card kicker: plain uppercase label, no underline */
.bento-tag {
  position: relative;
  display: inline-block;
  align-self: flex-start;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #9a9a9f;
  margin-bottom: 16px;
}
.bento-tag--dark { color: rgba(255, 255, 255, 0.6); }

/* Copychain tile: just the image, full-bleed */
/* capped aspect-ratio + align-self:start so this tile's tall source image can't
   blow out the whole grid row's height (grid rows auto-size to their tallest
   item's own preferred height, independent of stretch alignment) */
/* tall narrow column — the natural fit for this portrait image, no cropping hack needed */
.bento-card--tool-img { padding: 0; }
.bento-card--tool-img img { width: 100%; height: 100%; object-fit: cover; object-position: 15% top; display: block; }

/* text "button" floating in the center of preview cards */
.card-overlay-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: var(--white);
  color: var(--ink);
  font-weight: 600;
  font-size: 13.5px;
  padding: 11px 22px;
  border-radius: var(--radius-pill);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.2), 0 2px 6px rgba(0, 0, 0, 0.08);
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease), background 0.35s var(--ease);
  white-space: nowrap;
  max-width: calc(100% - 24px);
  box-sizing: border-box;
  z-index: 2;
}
.card-overlay-btn svg { transition: transform 0.35s var(--ease); }
.bento-card:hover .card-overlay-btn {
  transform: translate(-50%, -50%) scale(1.05);
  box-shadow: 0 16px 38px rgba(0, 0, 0, 0.3);
}
.bento-card:hover .card-overlay-btn svg {
  transform: translate(3px, -3px);
}

.bento-card--more { align-items: flex-start; }
.tool-chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 6px; }
.tool-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px 7px 8px;
  border-radius: var(--radius-pill); background: rgba(26,29,33,0.05); font-size: 12.5px; font-weight: 600; color: var(--ink);
}
.tool-chip .emoji { font-size: 14px; }

.bento-visual {
  aspect-ratio: 16/9; border-radius: 14px; overflow: hidden; position: relative;
  background: linear-gradient(155deg, var(--mint) 0%, #cdeed7 40%, var(--peach) 100%);
  display: flex; flex-direction: column; gap: 8px; padding: 16px;
  margin-bottom: 12px;
}
.bento-visual .chip { height: 8px; border-radius: 5px; background: rgba(26,29,33,0.16); }
.bento-visual .chip.w70 { width: 70%; } .bento-visual .chip.w45 { width: 45%; } .bento-visual .chip.w30 { width: 30%; }
.bento-visual--img { padding: 0; background: var(--white); aspect-ratio: 3/4; }
/* At desktop the card height is fixed by the grid — let the image grow to
   fill whatever room is left after the link below it, instead of a fixed
   ratio leaving a dead gap (see CMOrdle: image + a bottom play link only,
   no title/description eating space). */
@media (min-width: 1081px) {
  .bento-visual--img { aspect-ratio: auto; flex: 1 1 auto; min-height: 0; }
}

/* Solid-colour hero card — title + a solid CTA button, no image. For tools
   with no product screenshot worth cropping into a tiny preview box; the
   colour block itself fills the card, so there's no dead space to fight. */
.bento-card--solid { justify-content: center; gap: 18px; }
.bento-card--solid h3 { font-size: clamp(22px, 2.6vw, 30px); font-weight: 600; line-height: 1.25; margin-bottom: 0; }
.bento-card--solid .btn { align-self: flex-start; }
.bento-card--solid.bg-peach { background: var(--peach); border-color: transparent; }
.bento-card--solid.bg-mint { background: var(--mint); border-color: transparent; }
.bento-card--solid.bg-blue { background: var(--blue); border-color: transparent; color: var(--white); }

/* ChatGippity — full-width banner (span 4, one row) instead of a solo
   square: it's a text-only card (a parody wordmark + tagline, not a screen-
   shot), and the exact-packed 4-col grid above it has no leftover slot a
   solo card could sit in without leaving a gap next to it. A full row has
   nothing left over to gap. Colours lifted straight from the tool's own
   dark ChatGPT-clone UI. Not a bento card anymore — a slim single-line
   notice strip instead (see .chatgippity-bar below), so it doesn't compete
   with the grid above it for attention. */
.chatgippity-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px 20px;
  flex-wrap: wrap;
  margin-top: 20px;
  padding: 15px 26px;
  border-radius: var(--radius-md);
  /* #10a37f (the literal ChatGPT brand green) read right but couldn't carry
     white text at AA contrast (~3.2:1) — dropped one notch to this deeper
     shade instead of leaving the brand-green zone entirely, which clears
     white at ~4.96:1. */
  background: #0c7f63;
  color: #fff;
  text-decoration: none;
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}
.chatgippity-bar:hover { transform: translateY(-2px); box-shadow: var(--shadow-soft); }
.chatgippity-bar-text {
  font-size: 14.5px;
  line-height: 1.5;
  /* full white only on the bold lead-in; the follow-on sentence rides at
     0.9 (still clears AA at this size — dropping further starts to bite) */
  color: rgba(255,255,255,0.9);
}
/* the question carries the weight, the rest of the sentence rides along
   quieter — same bold-lead/soft-follow pattern as the site's other
   two-part copy (e.g. the footer column headers vs their sub-lines) */
.chatgippity-bar-text strong { font-weight: 700; color: #fff; }
.chatgippity-bar-cta {
  display: inline-flex; align-items: center; gap: 6px;
  flex-shrink: 0;
  padding: 8px 15px;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: 13.5px;
  font-weight: 700;
  transition: background 0.3s var(--ease);
}
.chatgippity-bar:hover .chatgippity-bar-cta { background: rgba(255, 255, 255, 0.28); }
.chatgippity-bar-cta svg { transition: transform 0.35s var(--ease); }
.chatgippity-bar:hover .chatgippity-bar-cta svg { transform: translate(3px, -3px); }

/* terminal mockup — for CLI tools with no product screenshot to show.
   Real window chrome (title bar + dots) instead of just floating dots,
   so it reads as an actual terminal and not a dark rectangle with text. */
.bento-visual--terminal { padding: 0; flex-direction: column; gap: 0; background: #16181b; }
/* full-bleed variant (bento-card--terminal): the terminal window IS the
   whole card, same treatment as the copychain tile — no aspect-ratio cap,
   fills whatever height the card's grid span gives it. */
.bento-card--terminal .bento-visual--terminal { aspect-ratio: auto; height: 100%; margin-bottom: 0; }
.term-bar {
  display: flex; align-items: center; gap: 6px; flex-shrink: 0;
  padding: 12px 14px; border-bottom: 1px solid rgba(255,255,255,0.08);
}
.term-dot { width: 9px; height: 9px; border-radius: 50%; }
.term-dot--red { background: #ff5f56; } .term-dot--yellow { background: #ffbd2e; } .term-dot--green { background: #27c93f; }
.term-bar-title {
  margin-left: 6px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px; color: rgba(255,255,255,0.35);
}
.term-body {
  flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 6px;
  padding: 16px 18px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px; line-height: 1.5;
}
.term-body .term-cmd { color: rgba(255,255,255,0.55); }
.term-body .term-comment { color: rgba(255,255,255,0.3); }
.term-body .term-pass { color: #4ade80; }
.term-body .term-fail { color: #fb7185; }
/* idle: only the typed command shows. hover: the rest of the audit output
   types in, staggered, like a real run — pure CSS, no JS/scroll involved. */
.term-line { opacity: 0; transform: translateY(4px); transition: opacity 0.3s var(--ease), transform 0.3s var(--ease); }
.term-line:first-child { opacity: 1; transform: none; }
.bento-card--terminal:hover .term-line { opacity: 1; transform: none; }
.bento-card--terminal:hover .term-line:nth-child(2) { transition-delay: 0.12s; }
.bento-card--terminal:hover .term-line:nth-child(3) { transition-delay: 0.3s; }
.bento-card--terminal:hover .term-line:nth-child(4) { transition-delay: 0.48s; }
.bento-card--terminal:hover .term-line:nth-child(5) { transition-delay: 0.66s; }
.bento-card--terminal:hover .term-line:nth-child(6) { transition-delay: 0.84s; }
.bento-visual--img img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }

@media (max-width: 1080px) {
  .bento-grid { grid-template-columns: repeat(2, 1fr); grid-auto-rows: minmax(270px, auto); }
  .bento-card, .bento--wide { grid-column: span 2; }
  /* Below desktop, rows should follow each card's own content instead of a
     fixed multiple of the desktop 270px unit — a fixed multiple is what
     caused the CTA-to-bottom spacing to drift card-to-card: huge leftover
     gap on the tall case study (content didn't fill 2 full rows), CTA
     clipped/overflowing past the bottom edge on the cards with longer
     paragraphs (content didn't fit 1 row). Auto rows plus .bento-link's
     base margin-top:auto now give every standalone card the same tight,
     content-hugging spacing with no per-card hack needed. The tall image
     showcase tile is the one exception that still wants the extra vertical
     room for its crop, so it keeps its 2-row span. */
  .bento--tall:not(.bento-card--tool-img) { grid-row: span 1; }
  /* insyde's hero tile is a landscape banner (~1.86:1), not a portrait
     showcase image like Copychain/CMOrdle — staying "tall" here just
     stretches the box into a portrait shape and forces a heavy side-crop.
     Collapse it like a normal card and pin its box to the image's own
     ratio instead, so cover-fit needs almost no crop at any width. */
  .bento--hero.bento-card--tool-img { grid-row: span 1; aspect-ratio: 1.864; }
  /* CMOrdle is a narrow portrait screenshot (~0.65:1) — the generic
     .bento-card rule above stretches it to the full 2-col width like
     every other card, and a portrait image at full width is inherently
     going to render very tall (736px wide -> 1139px tall) no matter what
     ratio math governs it. That's what was eating all the vertical space
     and reading as "way more spacing" below insyde. Keep it at half width
     here (still 2-row tall) instead of forcing it wide — a normal-looking
     narrow card, same as it already is at both desktop and ≤620px. */
  .bento-card--cmordle { grid-column: span 1; }
}
@media (max-width: 620px) {
  .bento-grid { grid-template-columns: 1fr; gap: 16px; grid-auto-rows: minmax(0, auto); }
  .bento-card, .bento--wide, .bento--hero, .bento--solo {
    grid-column: span 1 !important;
    grid-row: auto !important;
  }
  .bento-card--cmordle,
  .bento-card--photo,
  .bento-card--work-platform {
    aspect-ratio: 16 / 11;
  }
  .card-overlay-btn {
    padding: 10px 18px;
    font-size: 13px;
    max-width: calc(100% - 24px);
  }
}

/* ==========================================================================
   FAQ
   ========================================================================== */
.faq-section { padding: clamp(50px, 8vw, 90px) 0; }
.faq-list { display: flex; flex-direction: column; gap: 12px; }
.faq-item {
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 18px 24px;
  background: var(--bg);
}
.faq-item summary {
  cursor: pointer;
  list-style: none;
  font-family: var(--font-grotesk);
  font-weight: 500;
  font-size: 18px;
  letter-spacing: -0.01em;
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+";
  flex: none;
  font-size: 22px;
  font-weight: 300;
  color: var(--ink-soft);
  transition: transform 0.25s var(--ease);
}
.faq-item[open] summary::after { content: "\2212"; }
.faq-item p { margin-top: 14px; color: var(--ink-soft); font-size: 15.5px; line-height: 1.7; }
.faq-item p a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }

/* ==========================================================================
   Team
   ========================================================================== */
.team-section { padding: clamp(60px, 10vw, 130px) 0; }
.team-grid { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: clamp(30px, 5vw, 70px); align-items: start; }
.team-grid h2 { font-family: var(--font-grotesk); font-weight: 300; font-size: clamp(28px, 4.2vw, 44px); letter-spacing: -0.03em; line-height: 1.18; }
.team-grid h2 b { font-weight: 600; }
.team-copy p { font-size: 16px; line-height: 1.75; color: var(--ink-soft); margin-bottom: 22px; }
.team-copy .btn { margin-top: 10px; }

/* ==========================================================================
   Footer
   ========================================================================== */
.footer {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  margin-top: 40px;
  background: var(--blue);
  /* white-on-this-blue has meaningfully less contrast than white-on-ink —
     every text/border opacity below is bumped up from what it was on the
     dark background specifically to compensate; full white only clears
     ~4.1:1 here, so nothing translucent can go much lower than this and
     stay comfortably readable */
  color: rgba(255,255,255,0.92);
  /* bottom breathing room was noticeably tighter than the top (30px vs
     50-80px) — the page felt like it just stopped rather than closed */
  padding: clamp(50px, 8vw, 80px) 0 clamp(36px, 6vw, 60px);
}
/* Footer wash — full-bleed linear gradient, base-blue → deeper navy (both
   lifted off var(--blue), no white) at an angle (--fangle) that script.js
   rotates every frame to match the cursor's current direction of travel.
   No white here on purpose — the footer's own text/icons are already
   white, so a white gradient end was washing out against them instead of
   reading as a separate effect. mix-blend-mode:multiply instead of screen
   for the same reason: it should darken the blue, not lighten toward white.
   No shape, no blob, no blur-silhouette to contain it — this IS the
   footer's background texture, edge to edge, sitting under the real
   content (which stays unaffected, on its own z-index layer above this).
   Kept as a pseudo-element (not markup) so it applies to the footer on
   every page for free. */
.footer::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(var(--fangle, 135deg),
    rgba(74,127,196,0.35) 0%,
    rgba(47,74,133,0.3) 50%,
    rgba(20,32,64,0.35) 100%);
  mix-blend-mode: multiply;
  pointer-events: none;
  z-index: 0;
}
.footer > * { position: relative; z-index: 1; }
/* Row 1: Discuss-with-AI | Newsletter signup — side by side, each its own
   stacked label→copy→action block (Ada's footer reference). */
.footer-top-row { display: grid; grid-template-columns: 1.3fr 1fr; gap: 40px; }
.footer-ai { display: flex; flex-direction: column; align-items: flex-start; }
/* both column headers (this one + "Stay in the loop") and both description
   lines below them share one style each — .footer h4 / .footer-col-sub —
   so the two blocks read as a matched pair, not two different treatments */
.footer-col-sub { font-size: 14.5px; line-height: 1.6; color: rgba(255,255,255,0.92); max-width: 52ch; }
/* same top offset as .newsletter form below, so the icon row lines up with
   the email bar beside it once both description lines are a single line */
.footer-ai-icons { display: flex; gap: 10px; margin-top: 14px; }
.footer-ai-icons a {
  width: 38px; height: 38px; border-radius: 50%; background: rgba(255,255,255,0.16);
  display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,0.9);
  transition: background 0.3s var(--ease), color 0.3s var(--ease), transform 0.3s var(--ease);
}
.footer-ai-icons a:hover { background: rgba(255,255,255,0.28); color: var(--white); transform: translateY(-2px); }
.footer h4 { color: var(--white); font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 18px; }
.newsletter form { display: flex; gap: 8px; margin-top: 14px; }
.newsletter input {
  flex: 1; min-width: 0; padding: 12px 16px; border-radius: var(--radius-pill);
  border: 1px solid rgba(255,255,255,0.32); background: rgba(255,255,255,0.1); color: var(--white); font-size: 14px;
}
.newsletter input::placeholder { color: rgba(255,255,255,0.62); }
.newsletter input:focus { outline: none; border-color: var(--mint); }
.newsletter button {
  /* white on the dark footer, same treatment as .btn--light elsewhere —
     mint wasn't used as a CTA colour anywhere else on the site, just a
     couple of decorative accents, so it read as disconnected here */
  width: 44px; height: 44px; border-radius: 50%; border: none; background: var(--white); color: var(--ink);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: transform 0.3s var(--ease);
}
.newsletter button:hover { transform: scale(1.08); }

/* Row 2: big logo | brand line + social links | legal links list — three
   columns, vertically centered against each other. (Stretching the logo to
   match the text column's exact height, tried earlier, made it oversized
   once that column's content got shorter — a fixed, apt size centred
   against the row reads better than one that tracks sibling content.) */
.footer-brand-row {
  /* logo and legal-links both sized to their own content (max-content),
     not an fr share — an fr share on the logo column left a large dead
     gap between the (narrow) logo and the paragraph beside it, pushing
     the whole text block off toward the right instead of sitting close
     to the logo. The paragraph column is the only one that should flex. */
  display: grid; grid-template-columns: max-content 1fr max-content; gap: 40px; align-items: center;
  margin-top: 34px; padding-top: 34px; border-top: 1px solid rgba(255,255,255,0.22);
}
.footer-logo-big { display: block; }
.footer-logo-big .logo-img { height: clamp(46px, 5vw, 64px); width: auto; }
.footer-social { display: flex; gap: 26px; margin-top: 14px; flex-wrap: wrap; }
.footer-social a {
  font-size: 14px; text-decoration: underline; text-underline-offset: 4px;
  transition: color 0.3s var(--ease);
}
.footer-social a:hover { color: var(--white); }
/* top-aligned (not centered) so it starts flush with the brand paragraph
   beside it, instead of floating mid-height against top-aligned text */
.footer-legal-links { display: flex; flex-direction: column; gap: 13px; }
.footer-legal-links a {
  font-size: 14px; color: rgba(255,255,255,0.92); text-decoration: underline; text-underline-offset: 4px;
  transition: color 0.3s var(--ease);
}
.footer-legal-links a:hover { color: var(--white); }
@media (max-width: 560px) {
  .footer-top-row { grid-template-columns: 1fr; gap: 32px; }
  .footer-brand-row { grid-template-columns: 1fr; gap: 24px; }
}
.footer-bottom {
  max-width: var(--container); margin: 50px auto 0; padding: 22px clamp(20px, 5vw, 32px) 0;
  border-top: 1px solid rgba(255,255,255,0.22);
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px;
  font-size: 13px;
}
.footer-bottom a { transition: color 0.3s var(--ease); }
.footer-bottom a:hover { color: var(--white); }

/* ==========================================================================
   Reveal animation
   ========================================================================== */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.8s var(--ease), transform 0.8s var(--ease); }
.reveal.is-visible { opacity: 1; transform: translateY(0); }
.reveal-stagger.is-visible > * { opacity: 1; transform: translateY(0); }
.reveal-stagger > * { opacity: 0; transform: translateY(24px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
.reveal-stagger > *:nth-child(1) { transition-delay: 0.02s; }
.reveal-stagger > *:nth-child(2) { transition-delay: 0.10s; }
.reveal-stagger > *:nth-child(3) { transition-delay: 0.18s; }
.reveal-stagger > *:nth-child(4) { transition-delay: 0.26s; }

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 900px) {
  .nav-links { display: none; }
  /* .nav-links normally carries margin-left:auto to push the toggle to the
     right edge — with it display:none'd here, that push is lost, so the
     toggle needs its own margin-left:auto to stay pinned right of the logo */
  .nav-toggle { display: flex; margin-left: auto; }
  .stats-grid { grid-template-columns: 1fr; }
  .case-grid { grid-template-columns: 1fr; }
  .playground-card { grid-template-columns: 1fr; }
  .playground-visual { order: -1; }
  .team-grid { grid-template-columns: 1fr; }
  /* stacked, full-width paragraphs read as one dense block — pull the right edge
     in to shorten the line length; left stays flush with everything else on the
     page's left rail (nav, headings, cards) */
  .team-copy p { padding-right: 10%; }
  /* just two columns left now (brand, newsletter) — a side-by-side split
     leaves the newsletter looking oddly narrow, so stack them full-width */
  .footer .container { grid-template-columns: 1fr; }
  .device-side { display: none; }
  /* form submits (contact + jobs) — full-width tap target instead of a small
     left-aligned pill, matching the hero CTA stacking treatment */
  .btn--dark { width: 100%; justify-content: center; }
}
@media (max-width: 560px) {
  .newsletter form { flex-direction: row; }
}

/* ==========================================================================
   Sub-pages: page header
   ========================================================================== */
.page-hero { padding: clamp(56px, 10vw, 96px) 0 clamp(40px, 6vw, 64px); text-align: center; }
/* contact page only — real office footage as a plain, contained rounded
   card between the standard hero and the form. No overlay, no text on
   top of it — the title lives in the hero above now. Still tilts toward
   the cursor (script.js), it just doesn't need to carry text contrast. */
.contact-media { padding: 0 0 clamp(40px, 6vw, 64px); }
.page-hero-box {
  position: relative; overflow: hidden; isolation: isolate;
  border-radius: var(--radius-lg);
  /* explicit width:100% first — without it, once min-height's floor kicks in
     below the aspect-ratio's natural height (~144px at mobile widths), the
     box treats height as the known dimension and derives WIDTH from the
     21:9 ratio instead (320px × 21/9 ≈ 747px), blowing it out to roughly
     double the viewport and clipping everything inside */
  width: 100%;
  aspect-ratio: 21 / 9; min-height: 320px;
  display: flex; align-items: center; justify-content: center;
  perspective: 1000px;
}
.page-hero-video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  z-index: 0;
  /* scaled up so the cursor-tilt (JS) never reveals an edge; will-change keeps
     the constant transform writes off the main thread's paint path */
  transform: scale(1.14);
  will-change: transform;
}
.page-hero .eyebrow { display: block; }
.page-hero h1 { font-weight: 300; font-size: clamp(34px, 6vw, 60px); letter-spacing: -0.03em; line-height: 1.08; }
.page-hero h1 b { font-weight: 600; }
.page-hero p { margin: 18px auto 0; max-width: 52ch; color: var(--ink-soft); font-size: clamp(15px, 2vw, 18px); line-height: 1.65; }
.crumbs { display: flex; justify-content: center; gap: 8px; font-size: 13px; color: var(--ink-soft); margin-bottom: 22px; }
.crumbs a:hover { color: var(--ink); }
.crumbs span { opacity: 0.5; }

/* ==========================================================================
   Sub-pages: two column layout (info + form)
   ========================================================================== */
.split-section { padding: 0 0 clamp(70px, 10vw, 130px); }
/* contact page only — the video hero has no natural content buffer below it
   like a plain page-hero does, so give the form section real top breathing
   room instead of the fields starting right at the hero's edge */
/* the video box + this form read as one continuous unit, not two separate
   sections, so this shouldn't use the full inter-section gap scale — half it */
.split-section--plain { padding-top: clamp(28px, 4.5vw, 48px); }
/* minmax(0, ...) rather than plain fr — grid tracks default to a content
   min-width, and a full field-grid of inputs can be wide enough to push the
   form column past the container's right edge without it */
.split-grid { display: grid; grid-template-columns: minmax(0, 0.7fr) minmax(0, 1.1fr); gap: clamp(48px, 7vw, 90px); align-items: start; }
.info-card {
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: clamp(26px, 3.5vw, 36px); box-shadow: var(--shadow-soft);
}
.info-row { display: flex; gap: 16px; padding: 18px 0; border-bottom: 1px solid var(--line); }
.info-row:first-child { padding-top: 0; }
.info-row:last-child { border-bottom: none; padding-bottom: 0; }
.info-row .ico {
  width: 22px; height: 22px; flex-shrink: 0; margin-top: 19px;
  display: flex; align-items: center; justify-content: center;
  color: #4a7fc4;
}
.info-row h4 { font-size: 15px; font-weight: 700; margin: 0 0 6px; }
.info-row p, .info-row address { font-size: 14.5px; color: var(--ink-soft); line-height: 1.65; font-style: normal; margin: 0; }
.info-row a.inline-link { font-weight: 600; color: var(--purple); }
.info-row a.inline-link:hover { text-decoration: underline; }

.form-card {
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: clamp(26px, 4vw, 44px); box-shadow: var(--shadow-soft);
}
/* contact page only — not every content block needs to be a bordered/shadowed
   card; the row dividers and field borders already give this enough structure */
.split-section--plain .info-card,
.split-section--plain .form-card { background: none; border: none; border-radius: 0; box-shadow: none; padding: 0; }
.field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.field { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }
.field.full { grid-column: 1 / -1; }
.field label { font-size: 15px; font-weight: 600; color: var(--ink); }
.field label .req { color: #4a7fc4; font-weight: 700; }
.field input, .field select, .field textarea {
  width: 100%; padding: 13px 16px; border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong); background: var(--bg);
  font-family: var(--font-display); font-size: 14.5px; color: var(--ink);
  transition: border-color 0.3s var(--ease), background 0.3s var(--ease);
}
.field textarea { resize: vertical; min-height: 110px; }
/* Both selects on the site (jobs.html role, services.html service) were
   using the raw native <select> arrow with no extra right-padding reserved
   for it — different per-browser, but consistently rendered jammed against
   the field's own right edge with no breathing room. Custom chevron +
   appearance:none puts it under our own control, spaced to match how much
   room the left-side padding already gives text on the other side. */
.field select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%234f4f4f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 14px;
  cursor: pointer;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--purple); background: var(--white);
}
.field input::placeholder, .field textarea::placeholder { color: rgba(79,79,79,0.5); }
.form-note { font-size: 12.5px; color: var(--ink-soft); margin-top: 14px; }
.form-success {
  display: none; align-items: center; gap: 12px; padding: 16px 18px; border-radius: var(--radius-sm);
  background: rgba(161,228,178,0.28); color: #2c6b3f; font-size: 14px; font-weight: 600; margin-top: 16px;
}
.form-success.is-visible { display: flex; }
.form-error {
  display: none; align-items: center; gap: 12px; padding: 16px 18px; border-radius: var(--radius-sm);
  background: rgba(255, 200, 150, 0.3); color: #a3441a; font-size: 14px; font-weight: 600; margin-top: 16px;
}
.form-error.is-visible { display: flex; }
/* honeypot — kept in the layout (not display:none) so bots that skip hidden
   fields still fill it in, but positioned off-screen for real visitors */
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* ==========================================================================
   Sub-pages: jobs page — text-content cards + bento-style job cards
   ========================================================================== */
/* generic 3-column card grid for plain text content (how-we-work, benefits) —
   deliberately auto-height (no fixed grid-auto-rows like .bento-grid), so
   these cards just size to their own content instead of fighting a fixed
   row unit — that fixed-row/image collision is exactly what broke the
   Playground bento cards earlier, so this section avoids it entirely */
.card-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
/* reuses .bento-card's own look (padding/border/radius) — .bento--wide is
   just a grid-column span, safe to reuse outside the fixed-row bento-grid */
.card-grid-3 .bento-card { grid-column: span 1; }
.card-grid-3 .bento-card.bento--wide { grid-column: span 2; }
@media (max-width: 900px) { .card-grid-3 { grid-template-columns: repeat(2, 1fr); } .card-grid-3 .bento-card.bento--wide { grid-column: span 2; } }
@media (max-width: 560px) { .card-grid-3 { grid-template-columns: 1fr; } .card-grid-3 .bento-card.bento--wide { grid-column: span 1; } }

/* job cards — a plain, uniform 2-column grid (not bento) so all 5 cards
   match in size instead of fighting for a bento layout that never quite
   balanced with 5 items. The odd one out spans the full row instead of
   leaving a gap. */
/* "See open roles" text link (next to "That's the bar.") — on hover the
   down-arrow loops top-to-bottom: drops in from above, holds a beat, drops
   out below, repeats. The wrapper's fixed size + overflow:hidden is what
   masks the travel so it reads as the icon entering/exiting, not just
   sliding around loose. */
.open-roles-link {
  display: inline-flex; align-items: center; gap: 5px;
  font-weight: 600; color: var(--ink); text-decoration: underline; text-underline-offset: 2px;
}
.open-roles-arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; overflow: hidden;
}
.open-roles-link:hover .open-roles-arrow svg { animation: openRolesArrowDrop 0.9s ease-in-out infinite; }
@keyframes openRolesArrowDrop {
  0% { transform: translateY(-150%); opacity: 0; }
  35% { transform: translateY(0); opacity: 1; }
  65% { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(150%); opacity: 0; }
}

.jobs-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
.jobs-grid .job-card { grid-column: span 1; }
.jobs-grid .jobs-grid-full { grid-column: span 2; }
@media (max-width: 700px) { .jobs-grid { grid-template-columns: 1fr; } .jobs-grid .jobs-grid-full { grid-column: span 1; } }
.job-card .exp { display: block; margin-top: -6px; margin-bottom: 10px; font-size: 12.5px; color: var(--ink-soft); }
.job-card .bento-link { background: none; border: none; padding: 0; cursor: pointer; font-family: inherit; }

/* the equal-opportunity line — plain text, no card, no border, no shadow.
   Set further apart from the job cards above, with a heart to lead it in
   and the headline underlined in the heart's own red instead of a boxed
   callout — a quiet highlight, not another decorated component. */
.equal-op-line { color: var(--ink-soft); font-size: 14px; line-height: 1.7; margin-top: 48px; }
.equal-op-heart { margin-right: 4px; }
.equal-op-line strong { color: var(--ink); text-decoration: underline; text-decoration-color: #e0245e; text-underline-offset: 3px; }

/* "What we offer" — icon + text, no card/border around each item, a
   deliberate break from the boxed pattern used everywhere else on the page */
.offer-grid { display: flex; flex-wrap: wrap; gap: 28px 40px; }
.offer-item { display: flex; align-items: flex-start; gap: 14px; flex: 1 1 240px; }
.offer-ico {
  flex: none; width: 42px; height: 42px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.offer-ico svg { width: 20px; height: 20px; }
.offer-ico--purple { background: #f3ebff; color: #5b3cc4; }
.offer-ico--pink { background: #fff0f3; color: #d6336c; }
.offer-ico--green { background: #ebfbee; color: #2b8a3e; }
.offer-item h3 { font-size: 16px; font-weight: 600; margin-bottom: 4px; }
.offer-item p { font-size: 14px; color: var(--ink-soft); line-height: 1.6; margin: 0; }

/* ==========================================================================
   Sub-pages: jobs page — apply modal (full-page popup instead of an
   always-visible, always-shadowed inline form card)
   ========================================================================== */
.apply-modal {
  position: fixed; inset: 0; z-index: 600;
  background: rgba(26,29,33,0.5);
  display: flex; align-items: center; justify-content: center; padding: 24px;
  opacity: 0; pointer-events: none; transition: opacity 0.3s var(--ease);
}
.apply-modal.is-open { opacity: 1; pointer-events: auto; }
.apply-modal-box {
  position: relative; width: 100%; max-width: 640px; max-height: calc(100vh - 48px); overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--white); border-radius: var(--radius-lg); padding: clamp(28px, 4vw, 44px);
  transform: translateY(18px); transition: transform 0.35s var(--ease);
}
.apply-modal.is-open .apply-modal-box { transform: translateY(0); }
.apply-modal-close {
  position: absolute; top: 18px; right: 18px; width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; color: var(--ink-soft); cursor: pointer;
}
.apply-modal-close:hover { color: var(--ink); }

/* photo card with a title + CTA centred over a full-card dark wash —
   whole card is a <button> (opens the video modal), not a link. A uniform
   wash (not a bottom-anchored gradient band) keeps the text legible no
   matter where the overlay ends up sitting, instead of a hard edge
   cutting the card visibly in half. */
.bento-card--photo {
  padding: 0; position: relative; overflow: hidden;
  background-size: cover; background-position: center;
  border: none; cursor: pointer; text-align: left; font: inherit; color: inherit;
  display: flex; align-items: center; justify-content: center;
}
.bento-card--photo-overlay {
  position: absolute; inset: 0; z-index: 1; display: flex; flex-direction: column;
  align-items: flex-start; justify-content: center; gap: 14px; padding: 24px;
  background: rgba(0,0,0,0.42);
}
.bento-card--photo-overlay h3 { color: var(--white); margin-bottom: 0; }

/* video modal — same open/close pattern as .apply-modal, sized for video */
.video-modal {
  position: fixed; inset: 0; z-index: 600;
  background: rgba(26,29,33,0.85);
  display: flex; align-items: center; justify-content: center; padding: 24px;
  opacity: 0; pointer-events: none; transition: opacity 0.3s var(--ease);
}
.video-modal.is-open { opacity: 1; pointer-events: auto; }
.video-modal-box {
  position: relative; width: 100%; max-width: 900px;
  transform: translateY(18px); transition: transform 0.35s var(--ease);
}
.video-modal.is-open .video-modal-box { transform: translateY(0); }
.video-modal-box video { width: 100%; max-height: calc(100vh - 96px); border-radius: var(--radius-md); display: block; background: #000; }
.video-modal-close {
  position: absolute; top: -44px; right: 0; width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.15); border-radius: 50%; border: none; color: var(--white); cursor: pointer;
}
.video-modal-close:hover { background: rgba(255,255,255,0.28); }

/* ==========================================================================
   Sub-pages: playground tools
   ========================================================================== */
.playground-badge {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 15px; font-weight: 500; color: var(--ink-soft); margin-bottom: 32px;
}
.playground-badge img { width: 26px; height: 26px; display: block; }

@media (max-width: 900px) {
  .split-grid { grid-template-columns: 1fr; }
  .field-grid { grid-template-columns: 1fr; }
  .job-row { flex-direction: column; align-items: flex-start; }
}

/* ==========================================================================
   Services page: one detailed block per capability (list + case studies)
   ========================================================================== */
/* scoped to this page's hero only — the shared .page-hero h1 rule (DM Sans)
   still applies everywhere else (jobs.html, contact.html) */
.page-hero--services h1 { font-family: var(--font-grotesk); font-weight: 500; }
.service-block { padding: clamp(56px, 8vw, 90px) 0; border-top: 1px solid var(--line); }
.service-block:first-of-type { border-top: none; }
.service-head { max-width: 720px; margin-bottom: 40px; }

/* mascot rail — pinned on the left while the 4 service blocks scroll past
   on the right; script.js swaps .is-active between the 4 stacked images
   as each block crosses the middle of the viewport. Transparent PNGs, no
   card/border/shadow, they just float over the page background. */
.services-sticky-wrap { padding: clamp(56px, 8vw, 90px) 0 0; }
/* flexbox, not grid, for the sticky rail's container — CSS Grid's row-track
   auto-sizing has real cross-browser bugs with position:sticky children;
   flex + align-items:flex-start is the well-supported pattern. */
.services-sticky-grid { display: flex; gap: 56px; align-items: flex-start; }
.services-sticky-rail {
  position: sticky; top: 120px;
  flex: 0 0 360px; width: 360px; height: 420px;
  display: flex; align-items: center; justify-content: center;
}
.services-sticky-content { flex: 1; min-width: 0; }
.services-sticky-img {
  position: absolute; max-width: 100%; max-height: 100%;
  opacity: 0; transform: scale(0.96); transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
.services-sticky-img.is-active { opacity: 1; transform: scale(1); }
.services-sticky-content .service-block:first-of-type { padding-top: 0; }
@media (max-width: 900px) {
  .services-sticky-grid { flex-direction: column; }
  .services-sticky-rail { position: static; flex-basis: auto; width: auto; height: auto; margin-bottom: 32px; }
  .services-sticky-img { position: static; opacity: 1; transform: none; display: none; max-width: 260px; }
  .services-sticky-img.is-active { display: block; }
}
/* a lighter, smaller heading for sections that sit right under a page hero
   and shouldn't compete with it — same weight/scale relationship the hero
   already has with its own subtitle. .service-name (below) is deliberately
   heavier and is for services.html's own per-capability headings, which
   have a "01/02" number ahead of them establishing they're subsections;
   without that cue reusing the same weight reads as equal to the hero */
.section-heading-light {
  font-weight: 300; font-size: clamp(24px, 3.2vw, 34px); letter-spacing: -0.02em;
  line-height: 1.15; color: var(--ink); margin-bottom: 20px;
}
.section-heading-light b { font-weight: 600; }
.service-num {
  display: block; font-family: var(--font-grotesk); font-weight: 700; font-size: 13px;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--blue); margin-bottom: 10px;
}
/* the service name is the actual headline now — it was previously buried
   in the small "01 · Consulting" label with the tagline sized as the big
   h2 instead. Swapped: name is big + Host Grotesk, tagline demoted down
   to h4-ish size underneath it. */
.service-name {
  position: relative; display: inline-block;
  font-family: var(--font-grotesk); font-weight: 300; font-size: clamp(24px, 3.2vw, 36px);
  letter-spacing: -0.02em; line-height: 1.1; color: var(--ink); margin-bottom: 42px;
}
/* underline draws in left-to-right once the section scrolls into view —
   reuses the same .reveal/.is-visible mechanism already driving every
   other scroll animation on the site, no new JS needed. 14px clear of the
   descenders above and 14px clear of the tagline below — equidistant,
   rather than sitting closer to one side than the other. */
.service-name::after {
  content: ""; position: absolute; left: 0; bottom: -14px; height: 3px; width: 100%;
  background: var(--blue); border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.7s var(--ease) 0.15s;
}
.service-head.is-visible .service-name::after { transform: scaleX(1); }
.service-tagline { font-weight: 500; font-size: clamp(17px, 2vw, 21px); letter-spacing: -0.01em; line-height: 1.35; color: var(--ink-soft); margin-bottom: 14px; }
.service-tagline b { font-weight: 700; color: var(--ink); }
.service-head p { font-size: 16px; line-height: 1.7; color: var(--ink-soft); }
/* case studies sit below the list now, not beside it — the list gets the
   full container width instead of squeezed into ~55% of it */
.service-list { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px 24px; margin-bottom: 32px; }
.service-list li { position: relative; padding-left: 22px; font-size: 14.5px; color: var(--ink-soft); line-height: 1.6; }
.service-list li::before { content: ""; position: absolute; left: 0; top: 8px; width: 8px; height: 8px; border-radius: 2px; background: var(--blue); }
.service-cases { display: flex; flex-direction: row; flex-wrap: wrap; gap: 20px; align-items: stretch; }
.service-case-card {
  display: flex; flex-direction: column; flex: 1 1 320px; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 24px; transition: transform 0.35s var(--ease), border-color 0.35s var(--ease);
}
/* a light lift + border tint, not the heavy purple-tinted --shadow-lift —
   that read as the whole card jumping off the page */
.service-case-card:hover { transform: translateY(-3px); border-color: rgba(74,127,196,0.4); }
.service-case-tag { display: block; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: #9a9a9f; margin-bottom: 10px; }
.service-case-card h3 { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; margin-bottom: 8px; line-height: 1.35; }
.service-case-card p { font-size: 13.5px; color: var(--ink-soft); line-height: 1.6; margin-bottom: 10px; }
/* pinned to the card's bottom edge regardless of title/description length —
   same margin-top:auto-on-a-flex-column trick as .bento-link on the homepage */
.service-case-link { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; text-decoration: underline; text-underline-offset: 4px; margin-top: auto; padding-top: 4px; }
.service-case-link svg { transition: transform 0.3s var(--ease); }
.service-case-card:hover .service-case-link svg { transform: translate(3px, -3px); }
/* outline button, not filled — sits right above the case-study cards, so a
   solid fill would compete with them; hollow reads as one cohesive group
   with the cards instead of a separate, louder stop */
.service-cta { margin-bottom: 32px; }
@media (max-width: 900px) {
  .service-list { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .service-list { grid-template-columns: 1fr; }
}
/* waves twice once the lead-form heading scrolls into view — same
   .reveal/.is-visible scroll trigger used everywhere else on the site */
.wave-emoji { display: inline-block; transform-origin: 70% 70%; }
.section-head.is-visible .wave-emoji { animation: wave-hand 0.6s ease-in-out 0.3s 2; }
@keyframes wave-hand {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(16deg); }
  40% { transform: rotate(-10deg); }
  60% { transform: rotate(16deg); }
  80% { transform: rotate(-6deg); }
}
@media (prefers-reduced-motion: reduce) {
  .section-head.is-visible .wave-emoji { animation: none; }
}

/* ==========================================================================
   Playground: an index of what we've built, not a gimmick
   ========================================================================== */
/* the mock desktop IS the page — no title, no hero, no card framing it.
   Fills the space below the nav the way a real desktop fills the screen. */
.playground-main { display: block; }
.mac-desktop {
  position: relative; width: 100%; min-height: calc(100vh - 76px);
  padding: 40px;
  background: radial-gradient(120% 100% at 15% 0%, #e4d9f7 0%, var(--bg-deep) 45%, #d8ecf5 100%);
  overflow: hidden;
}
/* quiet hint that we're hiring — a little radar widget in the corner,
   the same "square app widget" shape as the Gemini widget. Draggable like
   the others; clicking it (without dragging) opens the jobs page. */
.playground-radar {
  position: absolute; top: 24px; left: 40px; z-index: 3; box-sizing: border-box;
  width: 165px; height: 165px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  padding: 15px; text-decoration: none; cursor: grab;
  background: radial-gradient(130% 110% at 30% 15%, #163524 0%, #0a1610 70%);
  border-radius: 20px; border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 20px 50px -25px rgba(6, 20, 10, 0.6);
}
.playground-radar:active { cursor: grabbing; }
.playground-radar-face {
  position: relative; width: 62px; height: 62px; border-radius: 50%; flex: 0 0 auto;
  background: radial-gradient(circle at 35% 30%, #123b22, #051309 72%);
  border: 2px solid rgba(255, 255, 255, 0.35);
  box-shadow: 0 6px 16px rgba(6, 20, 10, 0.35), inset 0 0 12px rgba(0, 0, 0, 0.55);
  overflow: hidden;
  transition: transform 0.2s ease;
}
.playground-radar:hover .playground-radar-face,
.playground-radar:focus-visible .playground-radar-face { transform: scale(1.08); }
.playground-radar-face::before,
.playground-radar-face::after {
  content: ""; position: absolute; border: 1px solid rgba(124, 255, 178, 0.3); border-radius: 50%;
}
.playground-radar-face::before { inset: 9px; }
.playground-radar-face::after { inset: 18px; }
.playground-radar-sweep {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 0deg, rgba(124, 255, 178, 0.7), rgba(124, 255, 178, 0) 30%);
  animation: playground-radar-spin 3s linear infinite;
}
@keyframes playground-radar-spin { to { transform: rotate(360deg); } }
.playground-radar-blip {
  position: absolute; left: var(--x); top: var(--y); width: 4px; height: 4px; border-radius: 50%;
  background: #7cffb2; box-shadow: 0 0 6px #7cffb2;
  opacity: 0; animation: playground-radar-blip 4.2s ease-in-out infinite; animation-delay: var(--delay);
}
@keyframes playground-radar-blip { 0%, 92%, 100% { opacity: 0; } 6%, 16% { opacity: 1; } }
/* the caption blinks like an active radar readout, not static label text */
.playground-radar-caption {
  font-size: 11.5px; line-height: 1.35; text-align: center; color: rgba(255, 255, 255, 0.8);
  animation: playground-radar-caption-blink 2.2s ease-in-out infinite;
}
@keyframes playground-radar-caption-blink { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } }
/* real macOS title bars blend into whatever the window's own content
   background is, not a fixed grey strip — each window sets --bar-bg
   to match its embedded page; --bar-bg falls back to the standard grey
   for the plain description-card windows that don't set it */
.mac-window-bar {
  position: relative; display: flex; align-items: center; gap: 8px; padding: 13px 14px; cursor: grab;
  background: var(--bar-bg, #ebebee); border-bottom: 1px solid var(--line);
}
.mac-window-bar:active { cursor: grabbing; }
.mac-dot { width: 11px; height: 11px; border-radius: 50%; border: none; padding: 0; flex: none; }
.mac-dot--red { background: #ff5f57; } .mac-dot--yellow { background: #febc2e; } .mac-dot--green { background: #28c840; }
/* the dots are only ever real buttons — close always works, yellow/green
   only appear on windows that have a real link to copy/open */
button.mac-dot { cursor: pointer; position: relative; }
/* pops down, not up — the title bar sits right at the modal's top edge,
   and every window clips overflow, so a tooltip above the dot has no
   room and gets cut off by the window's own corner */
button.mac-dot--yellow.is-copied::after {
  content: "Copied"; position: absolute; top: calc(100% + 9px); left: 50%; transform: translateX(-50%);
  white-space: nowrap; background: rgba(30,30,32,0.95); color: var(--white);
  font-size: 11px; font-weight: 500; padding: 4px 8px; border-radius: 6px; pointer-events: none; z-index: 5;
}
button.mac-dot--yellow.is-copied::before {
  content: ""; position: absolute; top: calc(100% + 4px); left: 50%; transform: translateX(-50%);
  border: 4px solid transparent; border-bottom-color: rgba(30,30,32,0.95); pointer-events: none; z-index: 5;
}
/* dark --bar-bg needs light title text instead of the default dark-on-light */
.mac-window-bar--dark { border-bottom-color: rgba(255,255,255,0.12); }
.mac-window-bar--dark .mac-window-url { color: rgba(255,255,255,0.82); }
/* plain title text, like a native app's window bar — not a browser chrome.
   Only the actual browser window (work.talkxo.com) gets the address-bar
   pill treatment; everything else is an "app", not a page inside a browser */
.mac-window-url { margin-left: 6px; font-size: 12.5px; font-weight: 600; color: var(--ink-soft); flex: 1; }
/* sized to its own text, not stretched to fill the bar — centered on the
   full bar width (ignoring the dots) like a real macOS address field */
.mac-window-url--browser {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  margin-left: 0; flex: none;
  width: max-content; max-width: calc(100% - 70px);
  background: var(--white); border-radius: var(--radius-sm); padding: 5px 18px;
  font-size: 12.5px; font-weight: 500; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* the Gemini widget — a small "app" sitting on the desktop, draggable.
   Square, like a real macOS widget's default size. */
.mac-widget {
  position: absolute; top: 24px; right: 40px; box-sizing: border-box; width: 165px; height: 165px;
  background: rgba(255,255,255,0.9); border-radius: 20px; border: 1px solid var(--line);
  box-shadow: 0 20px 50px -25px rgba(26,29,33,0.4); padding: 12px;
  backdrop-filter: blur(12px); cursor: grab;
  display: flex; flex-direction: column;
}
.mac-widget:active { cursor: grabbing; }
.mac-widget-head {
  display: flex; align-items: center; justify-content: center; gap: 5px; font-size: 10px; font-weight: 600; color: var(--ink-soft);
  margin-bottom: 7px; flex: 0 0 auto;
}
.mac-widget-head img { width: 12px; height: 12px; }
.mac-widget-grid {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr); gap: 6px;
}
.mac-widget-grid .lab-card { aspect-ratio: auto; }
.mac-widget-grid .lab-card { border-radius: 14px; }
/* the music widget — just the Spotify embed's own rounded UI, no white
   card or label wrapping it. Spotify's "compact" embed height (152px) is
   the smallest form the player comes in; 2x the width of the two square
   widgets since a horizontal player needs the room */
/* Spotify's embed snaps to its own numbered-tracklist layout past ~90px
   tall, and stretching the card taller than the iframe just adds empty
   black bars — neither looks good, so this stays its natural compact
   height instead of forcing a match to the two square cards */
/* Spotify's "tracklist visible" layout is genuinely clean only at its own
   152px breakpoint — taller than that just exposes a partial 4th track
   with no more real content, so 152 stays the height. Width matches 2
   grid units (165px each, same as the square widgets) for a proportional
   ~2×1 footprint */
.mac-widget-spotify {
  position: absolute; box-sizing: border-box; width: 330px; height: 352px;
  border-radius: 20px; overflow: hidden; cursor: grab;
  box-shadow: 0 20px 50px -25px rgba(26,29,33,0.4);
}
.mac-widget-spotify:active { cursor: grabbing; }
.mac-widget-spotify iframe { width: 100%; height: 100%; border: none; display: block; }
.mac-widget-spotify--empty {
  background: #121212; display: flex; align-items: center; justify-content: center;
  padding: 16px; text-align: center; font-size: 11px; line-height: 1.4; color: rgba(255, 255, 255, 0.55);
}
.mac-widget-grid .lab-name { font-size: 8.5px; }
.mac-widget-grid .lab-card svg { width: 20%; }
/* the cards shrank a lot — "Coming soon" was wrapping to 2 lines and,
   since the overlay is only 80% opaque, the name underneath ghosted
   through it. One line, and a near-opaque background instead. */
.mac-widget-grid .lab-soon {
  font-size: 7.5px; padding: 0 4px; white-space: nowrap; background: rgba(20, 20, 23, 0.94);
}

/* the dock — macOS-accurate: icon pops up + slightly grows on hover, a
   dark tooltip with a little pointer floats above it, exactly like the
   real thing, not just a plain label sitting under the icon */
.mac-dock {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  display: flex; gap: 16px; padding: 12px 18px; border-radius: var(--radius-lg);
  background: rgba(255,255,255,0.55); border: 1px solid rgba(255,255,255,0.6);
  backdrop-filter: blur(14px); box-shadow: 0 20px 40px -20px rgba(26,29,33,0.35);
}
.mac-dock-icon {
  position: relative; display: flex; flex-shrink: 0; background: none; border: none; cursor: pointer; padding: 0;
  transition: transform 0.2s var(--ease);
}
.mac-dock-icon:hover { transform: translateY(-12px) scale(1.18); }
.mac-dock-icon img {
  width: 52px; height: 52px; border-radius: 14px; object-fit: cover; object-position: top;
  box-shadow: 0 8px 18px -8px rgba(26,29,33,0.4);
}
.mac-dock-emoji {
  width: 52px; height: 52px; border-radius: 14px; background: var(--white);
  display: flex; align-items: center; justify-content: center; font-size: 26px;
  box-shadow: 0 8px 18px -8px rgba(26,29,33,0.4);
}
/* small transparent-PNG icons (not a screenshot) sit inside the same white
   tile as the emoji icons, padded so the glyph doesn't touch the edges */
.mac-dock-emoji--instagram { background: linear-gradient(135deg, #f9ce34, #ee2a7b 55%, #6228d7); }
.mac-dock-emoji--instagram svg { width: 60%; height: 60%; }
.mac-dock-emoji--copychain { background: #5b3cc4; }
.mac-dock-emoji--copychain svg { width: 46%; height: 46%; }
.mac-dock-emoji--cmordle { background: #e7d7c1; }
.mac-dock-emoji--cmordle svg { width: 50%; height: 50%; }
/* red notification dot — top-right of the icon, like an unread badge */
.mac-dock-notify {
  position: absolute; top: -3px; right: -3px; width: 13px; height: 13px; border-radius: 50%;
  background: #ff3b30; border: 2px solid rgba(255,255,255,0.9);
}
/* tooltip — dark pill floating above the icon, little triangle pointing
   down at it, only shown on hover (real macOS behaviour) */
.mac-dock-label {
  position: absolute; bottom: calc(100% + 14px); left: 50%; transform: translateX(-50%);
  white-space: nowrap; background: rgba(30,30,32,0.95); color: var(--white);
  font-size: 12.5px; font-weight: 500; padding: 5px 10px; border-radius: 7px;
  opacity: 0; pointer-events: none; transition: opacity 0.15s var(--ease);
}
.mac-dock-label::after {
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: rgba(30,30,32,0.95);
}
.mac-dock-icon:hover .mac-dock-label { opacity: 1; }

/* windows the dock opens — live ON the desktop itself, not a page-covering
   popup: no dimmed backdrop, positioned/draggable within the same bounds
   as the widget, several can be open side by side like real windows */
.mac-modal {
  display: none; position: absolute; width: min(360px, 60%); max-height: calc(100% - 20px); overflow-y: auto;
  background: var(--white); border-radius: 20px; box-shadow: 0 30px 70px -25px rgba(26,29,33,0.5);
  z-index: 10;
}
.mac-modal.is-active { display: block; }
/* CMOrdle plays live inside its own window instead of just linking out —
   wider/taller than the description-style windows, and the frame is edge
   to edge with no padding, like a real embedded app rather than a card.
   overflow:hidden on the window itself — only the embedded page scrolls,
   not the window chrome around it, so there's never a double scrollbar */
.mac-modal--game { width: min(460px, 85%); height: min(780px, calc(100% - 20px)); flex-direction: column; overflow: hidden; }
.mac-modal--game.is-active { display: flex; }
/* Copychain is a canvas tool — needs more horizontal room than a phone-shaped game window */
.mac-modal--wide { width: min(640px, 90%); height: min(600px, calc(100% - 20px)); flex-direction: column; overflow: hidden; }
.mac-modal--wide.is-active { display: flex; }
/* the embedded Instagram post — same single-scrollbar treatment, and
   zoomed out slightly so the whole card fits with less scrolling */
.mac-modal--insta { width: min(420px, 85%); height: min(680px, calc(100% - 20px)); flex-direction: column; overflow: hidden; }
.mac-modal--insta.is-active { display: flex; }
.mac-modal--insta .mac-modal-body {
  flex: 1; min-height: 0; overflow-y: auto; padding: 16px;
  display: flex; justify-content: center;
  zoom: 0.85;
}
/* a window that's just a photo, edge to edge — no padding, no text */
.mac-modal--image { width: min(480px, 85%); overflow: hidden; }
.mac-modal-image { display: block; width: 100%; height: auto; }
/* these tools are already responsive at the window's own size — scaling
   the iframe shifted its content off-center (empty space on one side)
   instead of helping, so it's embedded at its natural 1:1 size */
.mac-modal-frame { flex: 1; min-height: 0; overflow: hidden; }
.mac-modal-frame iframe { width: 100%; height: 100%; border: none; display: block; }
/* a thinner, quieter scrollbar than the default OS one, wherever a window
   does need to scroll */
.mac-modal-body::-webkit-scrollbar, .mac-modal::-webkit-scrollbar { width: 8px; }
.mac-modal-body::-webkit-scrollbar-thumb, .mac-modal::-webkit-scrollbar-thumb { background: rgba(26,29,33,0.18); border-radius: 4px; }
.mac-modal-body::-webkit-scrollbar-track, .mac-modal::-webkit-scrollbar-track { background: transparent; }
.mac-modal-frame iframe { width: 100%; height: 100%; border: none; display: block; }
.mac-modal-body { padding: 24px; }
.mac-modal-body img { width: 100%; border-radius: var(--radius-sm); margin-bottom: 16px; background: var(--bg-deep); object-fit: contain; }
.mac-modal-body .tool-showcase-visual { border-radius: var(--radius-sm); margin-bottom: 16px; }
.mac-modal-body h3 { font-size: 19px; font-weight: 600; letter-spacing: -0.005em; margin-bottom: 8px; }
.mac-modal-body p { font-size: 14.5px; color: var(--ink-soft); line-height: 1.65; margin-bottom: 16px; }
.tool-showcase-tag { display: block; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: #9a9a9f; margin-bottom: 8px; }
.tool-showcase-visual {
  aspect-ratio: 16/10; background: linear-gradient(155deg, var(--mint) 0%, #cdeed7 40%, var(--peach) 100%);
  display: flex; flex-direction: column; justify-content: center; gap: 10px; padding: 20px;
}
.tool-showcase-visual .chip { height: 9px; border-radius: 5px; background: rgba(26,29,33,0.18); }
.tool-showcase-visual .chip.w70 { width: 70%; } .tool-showcase-visual .chip.w45 { width: 45%; } .tool-showcase-visual .chip.w30 { width: 30%; }

/* the Made for Gemini tiles — used both inside the Playground's mock
   widget (playground-lab.html) and full-size on the standard Playground
   page below */
.concept-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
@media (max-width: 760px) { .concept-grid { grid-template-columns: repeat(2, 1fr); } }
.lab-card {
  position: relative; aspect-ratio: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 10px; border-radius: 20px; border: none; cursor: pointer; overflow: hidden;
  text-decoration: none; color: inherit;
}
/* card frame itself stays put — only the icon zooms in, contained within it */
.lab-card svg { width: 26%; height: 26%; max-width: 34px; max-height: 34px; fill: none; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.4s var(--ease); }
.lab-card:hover svg { transform: scale(1.25); }
.lab-name { font-size: clamp(12.5px, 1.5vw, 14px); font-weight: 500; }
.lab-card--purple { background: #f3ebff; } .lab-card--purple svg, .lab-card--purple .lab-name { color: #5b3cc4; stroke: #5b3cc4; }
.lab-card--pink   { background: #fff0f3; } .lab-card--pink svg,   .lab-card--pink .lab-name   { color: #d6336c; stroke: #d6336c; }
.lab-card--green  { background: #ebfbee; } .lab-card--green svg,  .lab-card--green .lab-name  { color: #2b8a3e; stroke: #2b8a3e; }
.lab-soon {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(26,29,33,0.8); color: var(--white); font-size: 11.5px; font-weight: 600;
  opacity: 0; transition: opacity 0.3s var(--ease); pointer-events: none;
}
.lab-card:hover .lab-soon { opacity: 1; }

@media (max-width: 760px) {
  /* the free-positioned desktop metaphor doesn't survive a narrow screen —
     same instinct as the canvas mobile fallback: drop the absolute layout,
     stack everything in normal flow instead of forcing it into place */
  .mac-desktop { display: flex; flex-direction: column; gap: 16px; min-height: 0; padding: 20px; }
  .playground-radar { position: static; align-self: flex-start; width: 140px; height: 140px; }
  .mac-widget { position: static; width: 100%; max-width: none; height: auto; }
  .mac-widget-spotify { position: static; width: 100%; }
  /* 6 icons no longer fit a phone width at full size — let the dock
     scroll horizontally instead of squashing the icons */
  .mac-dock { position: static; transform: none; width: 100%; box-sizing: border-box; justify-content: flex-start; order: -1; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .mac-dock-icon img, .mac-dock-emoji { width: 46px; height: 46px; }
  .mac-widget-grid { grid-template-columns: repeat(4, 1fr); grid-template-rows: none; }
  .mac-widget-grid .lab-card { aspect-ratio: 1; }
  .mac-modal.is-active { position: static; width: 100%; max-width: none; max-height: none; }
}

/* ==========================================================================
   CMOrdle promo toast + full-screen game modal (sitewide)
   ========================================================================== */
.cmordle-toast {
  position: fixed; z-index: 500; right: 24px; bottom: 24px;
  width: min(360px, calc(100vw - 48px));
  /* same liquid-glass treatment as the nav: translucent + blurred backdrop,
     plus the reliable (non-backdrop-filter-dependent) grain/specular/
     prismatic-edge layers below, instead of a solid opaque card. */
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(24px);
  color: var(--ink);
  border-radius: 20px; padding: 22px 24px 24px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.7),
    inset 0 -1px 0 rgba(26, 29, 33, 0.03),
    0 4px 16px rgba(26, 29, 33, 0.14), 0 30px 70px -25px rgba(0, 0, 0, 0.3);
  overflow: hidden;
  opacity: 0; transform: translateY(16px);
  pointer-events: none;
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
.cmordle-toast.is-visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
.cmordle-toast::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    radial-gradient(120% 140% at 12% 0%, rgba(255, 255, 255, 0.55), transparent 55%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.02 0'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: no-repeat, repeat;
  mix-blend-mode: overlay;
}
.cmordle-toast::after {
  content: ""; position: absolute; left: 10%; right: 10%; bottom: 0; height: 1px; z-index: 1; pointer-events: none;
  background: linear-gradient(90deg,
    rgba(255, 200, 210, 0.5) 0%, rgba(255, 240, 200, 0.4) 25%,
    rgba(200, 240, 220, 0.4) 50%, rgba(200, 220, 255, 0.45) 75%,
    rgba(230, 200, 255, 0.4) 100%);
}
/* flex row instead of absolute-positioning the close button independently
   of the title — that relied on guessing pixel offsets that matched neither
   font's actual metrics and never quite lined up */
.cmordle-toast-head { position: relative; z-index: 1; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.cmordle-toast-close {
  flex-shrink: 0; width: 26px; height: 26px; margin-top: -3px; margin-right: -6px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; color: #4a7fc4; cursor: pointer;
  border-radius: 50%; transition: background 0.25s var(--ease), color 0.25s var(--ease);
}
.cmordle-toast-close:hover { background: var(--bg); color: var(--ink); }
.cmordle-toast h4 { position: relative; font-size: 18px; font-weight: 600; letter-spacing: -0.01em; margin: 0; color: var(--ink); }
/* no artificial ch cap — that was forcing an early wrap and leaving the
   right side of the card empty even though the card itself was wide enough */
.cmordle-toast p { position: relative; font-size: 14px; line-height: 1.55; color: var(--ink-soft); margin: 0 0 14px; }
/* plain underlined text link, not a pill button — matches the same link
   style used on the work cards (.bento-link), and takes far less room */
.cmordle-toast-btn {
  position: relative; display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none; padding: 0; border-radius: 0;
  color: #4a7fc4; font-size: 13.5px; font-weight: 600; cursor: pointer;
  font-family: inherit; text-decoration: underline; text-underline-offset: 4px;
  transition: opacity 0.25s var(--ease);
}
.cmordle-toast-btn:hover { opacity: 0.75; }
.cmordle-toast-btn svg { transition: transform 0.25s var(--ease); }
.cmordle-toast-btn:hover svg { transform: translateX(3px); }

/* minimized state: closing the toast doesn't remove it, it collapses to this
   small round pill in the same corner. Solid white, and the shadow is
   deliberately soft/wide/low-opacity — spread, not a hard ring — the earlier
   version of this used a solid dark circle with a heavy shadow that read as
   a metallic badge, not a quiet minimized control. */
.cmordle-pill {
  position: fixed; z-index: 500; right: 24px; bottom: 24px;
  width: 52px; height: 52px; border-radius: 50%;
  background: #ffffff; border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 30px -8px rgba(26,29,33,0.16), 0 2px 10px rgba(26,29,33,0.06);
  opacity: 0; transform: scale(0.85);
  pointer-events: none;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease), box-shadow 0.3s var(--ease);
}
.cmordle-pill.is-visible { opacity: 1; transform: scale(1); pointer-events: auto; }
.cmordle-pill:hover { box-shadow: 0 14px 38px -8px rgba(26,29,33,0.22), 0 2px 12px rgba(26,29,33,0.08); }
.cmordle-pill-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 3px; width: 20px; height: 20px; }
.cmordle-pill-grid span { border-radius: 3px; background: #4a7fc4; }
.cmordle-pill-grid span:nth-child(2), .cmordle-pill-grid span:nth-child(3) { opacity: 0.5; }

.cmordle-modal {
  position: fixed; inset: 0; z-index: 600;
  background: #0a0a0c;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity 0.3s var(--ease);
}
.cmordle-modal.is-open { opacity: 1; pointer-events: auto; }
.cmordle-modal-frame-wrap {
  position: relative; width: 100%; height: 100%;
  background: #e7d7c1;
}
.cmordle-modal iframe { width: 100%; height: 100%; border: none; display: block; }
/* the game has its own "CMOrdle" title (top-left) and "How it works" link
   (top-right) inside the iframe — putting our close button in either top
   corner sits right on top of one of those, so it lives bottom-right instead,
   away from the game's own header entirely */
.cmordle-modal-close {
  /* top-right — the game's own "How it works" moved to a persistent link at
     the bottom of the page (see cmordle.html), so this corner is free now.
     Bottom-right used to collide with the game's own Next/Share buttons.
     Plain grey icon, no circle/shadow — the solid dark button with a heavy
     shadow read as an alarm, not a quiet close control. */
  position: absolute; top: 18px; right: 18px; z-index: 2; width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  background: none; color: rgba(44,36,25,0.55); border: none; cursor: pointer;
  transition: color 0.25s var(--ease);
}
.cmordle-modal-close:hover { color: rgba(44,36,25,0.9); }

@media (max-width: 560px) {
  /* noticeably smaller and less dominant on a small screen — was taking up
     a disproportionate share of the viewport */
  .cmordle-toast { left: auto; right: 12px; bottom: 12px; width: auto; max-width: min(240px, calc(100vw - 24px)); padding: 14px 16px 16px; border-radius: 14px; }
  .cmordle-toast h4 { font-size: 14px; margin-bottom: 5px; }
  .cmordle-toast p { font-size: 11.5px; margin-bottom: 12px; }
  .cmordle-toast-btn { font-size: 11.5px; }
  .cmordle-pill { right: 12px; bottom: 12px; width: 46px; height: 46px; }
  .cmordle-pill-grid { width: 17px; height: 17px; }
}
@media (prefers-reduced-motion: reduce) {
  .cmordle-toast { transition: opacity 0.3s var(--ease); transform: none !important; }
  .cmordle-toast.is-visible { transform: none; }
}
