/* ==========================================================================
   Heaviside Labs
   Pure-white technical theme. Vanilla CSS, no framework, no normalize.

   Design contract
   ---------------
   Ground      : #FFFFFF. Boundaries are 1px rules or space. The one heavier
                 surface is ink (--ink-surface), used for feature panels only
                 (one audience panel, one bento cell), never a whole section.
   Ink         : #0E1116 primary, #4A5560 secondary, #6B7684 muted.
   Accent      : #10457A navy, single and locked. Lifts to #8FB4D6 on ink.
   Radius lock : full pill on everything interactive and on tags; 16px on
                 surfaces (cards, panels, dialog). Nothing else.
   Type        : Schibsted Grotesk display + body, IBM Plex Mono for labels
                 and data.
   Motion      : entry choreography, scroll reveals, count-ups, a scroll-drawn
                 process line, pointer spotlight and a live hero canvas. All of
                 it is gated on html.motion (set in <head>), so reduced-motion
                 visitors get the final state with nothing moving.
   Theme lock  : light only; color-scheme is pinned.
   Z-index     : 50 topbar, 60 scroll progress, 100 skip link. Nothing else.
   ========================================================================== */

:root {
  color-scheme: light;

  --ground: #ffffff;
  --wash: rgb(14 17 22 / 0.045);

  --ink: #0e1116;
  --ink-2: #4a5560;
  --ink-3: #6b7684;

  --rule: #e2e5e9;
  --rule-strong: #cdd3da;

  --accent: #10457a;
  --accent-hover: #0b3459;
  --accent-tint: #eef3f8;
  --accent-ring: rgb(16 69 122 / 0.14);

  --ink-surface: #0e1116;
  --on-dark: #f3f5f7;
  --on-dark-2: #a9b3be;
  --accent-on-dark: #8fb4d6;
  --rule-on-dark: rgb(255 255 255 / 0.12);

  --r-pill: 999px;
  --r-surface: 16px;

  --lift: 0 24px 60px -12px rgb(14 17 22 / 0.18), 0 2px 6px rgb(14 17 22 / 0.05);

  --font-sans: 'Schibsted Grotesk', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --topbar-h: 68px;
  --section-y: clamp(4rem, 7.5vw, 6.5rem);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
}

/* ==========================================================================
   Reset
   ========================================================================== */

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

html {
  background-color: var(--ground);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--topbar-h) + 1.5rem);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background-color: var(--ground);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img, svg, canvas { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
dialog { color: inherit; }

::selection { background: var(--accent); color: #fff; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.ico { display: inline-flex; width: 1.15em; height: 1.15em; flex: none; }
.ico svg { width: 100%; height: 100%; }

/* ==========================================================================
   Layout primitives
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: 2200px;
  margin-inline: auto;
  padding-inline: 1.25rem;
}
@media (min-width: 768px) { .wrap { padding-inline: 2rem; } }
@media (min-width: 1100px) { .wrap { padding-inline: clamp(2.5rem, 5vw, 6rem); } }

.section { padding-block: var(--section-y); }

.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 100;
  padding: 0.625rem 1rem;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: #fff;
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: 12px; }

/* ==========================================================================
   Type
   ========================================================================== */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}
.eyebrow::before {
  content: '';
  width: 20px;
  height: 1px;
  background: currentColor;
}

.display {
  font-size: clamp(2.4rem, 4.5vw, 4.5rem);
  font-weight: 600;
  line-height: 1.06;
  letter-spacing: -0.04em;
  text-wrap: balance;
}

.h2 {
  font-size: clamp(1.9rem, 3.3vw, 3.25rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.032em;
  text-wrap: balance;
  max-width: 22ch;
}

.sub {
  margin-top: 1rem;
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 56ch;
  text-wrap: pretty;
}

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

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  height: 46px;
  padding-inline: 1.35rem;
  border-radius: var(--r-pill);
  font-size: 0.95rem;
  font-weight: 500;
  white-space: nowrap;
  transition:
    transform 0.5s var(--ease),
    color 0.25s ease,
    box-shadow 0.25s ease;
}
.btn:active { transform: translateY(1px) scale(0.98); }
.btn-sm { height: 40px; padding-inline: 1.1rem; font-size: 0.875rem; }
.btn-lg { height: 52px; padding-inline: 1.6rem; font-size: 1rem; }

/* Primary: ink at rest, navy floods in from the left on hover. */
.btn-primary { background: var(--ink); color: #fff; }
.btn-primary::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.55s var(--ease);
}
.btn-primary:hover::before,
.btn-primary:focus-visible::before { transform: scaleX(1); }

.btn-arrow { transition: transform 0.45s var(--ease); }
.btn:hover .btn-arrow { transform: translateX(3px); }

.btn-ghost {
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--rule-strong);
}
.btn-ghost:hover { box-shadow: inset 0 0 0 1px var(--ink); }

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: var(--r-pill);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--rule-strong);
  transition: background-color 0.25s ease, color 0.25s ease, box-shadow 0.25s ease, transform 0.4s var(--ease);
}
.icon-btn .ico { width: 18px; height: 18px; }
.icon-btn:hover:not(:disabled) { background: var(--ink); color: #fff; box-shadow: inset 0 0 0 1px var(--ink); }
.icon-btn:active:not(:disabled) { transform: scale(0.94); }
.icon-btn:disabled { opacity: 0.35; cursor: default; }

/* ==========================================================================
   Scroll progress (CSS scroll-driven; absent where unsupported)
   ========================================================================== */

.scroll-progress {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
  display: none;
}
@supports (animation-timeline: scroll()) {
  .motion .scroll-progress {
    display: block;
    animation: progress linear both;
    animation-timeline: scroll(root);
  }
}
@keyframes progress { to { transform: scaleX(1); } }

/* ==========================================================================
   Top bar
   ========================================================================== */

.topbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  transition: background-color 0.35s ease, box-shadow 0.35s ease;
}
.topbar.is-scrolled,
.topbar.menu-open {
  background: rgb(255 255 255 / 0.8);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
  box-shadow: 0 1px 0 var(--rule);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .topbar.is-scrolled, .topbar.menu-open { background: #fff; }
}

.topbar-inner {
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: -0.025em;
}
.brand-mark { width: 28px; height: 28px; transition: transform 0.6s var(--ease); }
.brand:hover .brand-mark { transform: rotate(-8deg) scale(1.06); }

.nav {
  position: relative;
  display: none;
  align-items: center;
  margin-left: auto;
  padding: 4px;
}
.nav-link {
  position: relative;
  z-index: 1;
  padding: 0.45rem 0.95rem;
  border-radius: var(--r-pill);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink-2);
  transition: color 0.25s ease;
}
.nav-link:hover,
.nav-link.is-active { color: var(--ink); }

/* One pill slides between links: it follows the hovered link and settles on
   the section currently in view. The layer spans the whole nav and JS moves
   a clip-path window over it, so the slide is paint-only (no width change). */
.nav-indicator {
  position: absolute;
  inset: 4px;
  border-radius: var(--r-pill);
  background: var(--wash);
  clip-path: inset(0 100% 0 0 round var(--r-pill));
  opacity: 0;
  transition: clip-path 0.5s var(--ease), opacity 0.3s ease;
}

.topbar-actions { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; }
.cta-desktop { display: none; }

.menu-toggle {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--r-pill);
  box-shadow: inset 0 0 0 1px var(--rule-strong);
}
.menu-toggle .ico { grid-area: 1 / 1; width: 20px; height: 20px; transition: opacity 0.25s ease, transform 0.4s var(--ease); }
.menu-toggle .ico-close { opacity: 0; transform: rotate(-90deg); }
.menu-toggle[aria-expanded='true'] .ico-open { opacity: 0; transform: rotate(90deg); }
.menu-toggle[aria-expanded='true'] .ico-close { opacity: 1; transform: none; }

.mobile-menu {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s var(--ease);
}
.mobile-menu.is-open { grid-template-rows: 1fr; }
.mobile-menu-clip { overflow: hidden; min-height: 0; }
.mobile-menu-inner {
  display: flex;
  flex-direction: column;
  padding-block: 0.5rem 1.5rem;
}
.mobile-link {
  padding-block: 0.8rem;
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  border-bottom: 1px solid var(--rule);
}
.mobile-cta { margin-top: 1.25rem; width: 100%; }
.motion .mobile-link {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.4s ease, transform 0.6s var(--ease);
}
.motion .mobile-menu.is-open .mobile-link {
  opacity: 1;
  transform: none;
  transition-delay: calc(80ms + var(--i) * 50ms);
}

@media (min-width: 900px) {
  .nav { display: flex; }
  .topbar-actions { margin-left: 0.5rem; }
  .cta-desktop { display: inline-flex; }
  .menu-toggle, .mobile-menu { display: none; }
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  display: flex;
  align-items: center;
  min-height: min(88dvh, 800px);
  padding-top: calc(var(--topbar-h) + clamp(2rem, 5vw, 4rem));
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}
.hero > .wrap { width: 100%; }

.hero-grid {
  display: grid;
  gap: 2.5rem;
  align-items: center;
}
@media (min-width: 960px) {
  .hero-grid { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 3rem; }
}

.hero-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
}

/* Word-by-word rise. Each word is clipped by its own box, with a little
   bottom reserve so descenders are never shaved. */
.display .word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: 0.1em;
  margin-bottom: -0.1em;
}
.display .word > span { display: inline-block; }
.accent-word { color: var(--accent); }

.lede {
  font-size: clamp(1.05rem, 1.35vw, 1.3rem);
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 42ch;
}

.hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 0.5rem; }

.hero-visual {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 11;
}
@media (min-width: 960px) {
  .hero-visual { aspect-ratio: 1; max-width: 640px; justify-self: end; }
}
.signal-field { width: 100%; height: 100%; cursor: crosshair; touch-action: pan-y; }

.motion .display .word > span {
  transform: translateY(108%);
  animation: word-rise 1s var(--ease) forwards;
  animation-delay: calc(120ms + var(--i) * 45ms);
}
.motion .hero-in {
  opacity: 0;
  transform: translateY(14px);
  animation: rise 0.9s var(--ease) forwards;
  animation-delay: var(--d, 0ms);
}
.motion .hero-visual {
  opacity: 0;
  animation: fade 1.4s ease 0.15s forwards;
}
@keyframes word-rise { to { transform: none; } }
@keyframes rise { to { opacity: 1; transform: none; } }
@keyframes fade { to { opacity: 1; } }

/* ==========================================================================
   Scroll reveal
   ========================================================================== */

.motion .reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.9s var(--ease), transform 1s var(--ease);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.motion .reveal.is-visible { opacity: 1; transform: none; }

/* ==========================================================================
   Pointer spotlight (cards and panels)
   A radial light follows the cursor across the surface and lights the 1px
   border under it. --mx / --my are set by JS on fine pointers only.
   ========================================================================== */

.spot { position: relative; isolation: isolate; }
.spot::before,
.spot::after {
  content: '';
  position: absolute;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
}
.spot::before {
  inset: 0;
  z-index: -1;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%), rgb(16 69 122 / 0.07), transparent 55%);
}
.spot::after {
  inset: -1px;
  padding: 1px;
  background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 50%), var(--accent), transparent 60%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.spot:hover::before,
.spot:hover::after { opacity: 1; }

/* ==========================================================================
   Proof: logo wall + metrics
   ========================================================================== */

/* Engagements flows straight into the testimonials, so it drops its bottom
   padding rather than doubling the gap between two related sections. The
   section heading names the logos, so the row carries no label of its own. */
.engagements { padding-bottom: 0; }

.proof-logos {
  padding-block: 1.75rem;
  border-block: 1px solid var(--rule);
}

/* Up to 6 clients: a static row that sizes itself to the count (--n, set in
   proof.html). Narrower screens wrap 2 or 3 per line with any odd logo
   centred on the last line, never stranded at the left. */
.logo-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 1.25rem 2rem;
}
.logo-row .logo-cell { flex: 0 0 calc((100% - 2rem) / 2); }
@media (min-width: 640px) {
  .logo-row .logo-cell {
    flex-basis: calc((100% - (var(--cols-md, 3) - 1) * 2rem) / var(--cols-md, 3));
  }
}
@media (min-width: 900px) {
  .logo-row { display: grid; grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); }
}

/* Marquee (engagements.html always; proof.html from 7 clients). Two identical sets, each ending in the same gap it
   uses between logos, so translating the track by exactly -50% loops with no
   seam. Speed scales with the count (--marquee-duration). Pauses on hover
   and focus. Without html.motion it collapses to one static, wrapped set. */
.logo-marquee {
  min-width: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
.logo-track { display: flex; width: max-content; }
.logo-set { display: flex; align-items: center; gap: 3rem; padding-right: 3rem; }
.logo-set .logo-cell { flex: none; width: 140px; }
.motion .logo-track { animation: marquee var(--marquee-duration, 30s) linear infinite; }
.logo-marquee:hover .logo-track,
.logo-marquee:focus-within .logo-track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(-50%); } }

html:not(.motion) .logo-marquee { -webkit-mask-image: none; mask-image: none; }
html:not(.motion) .logo-track { width: auto; }
html:not(.motion) .logo-set { flex-wrap: wrap; justify-content: center; row-gap: 1.25rem; padding-right: 0; }
html:not(.motion) .logo-set[aria-hidden='true'],
html:not(.motion) .logo-cell[aria-hidden='true'] { display: none; }
.logo-cell { display: flex; align-items: center; justify-content: center; height: 56px; }
.logo-cell img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: calc(32px * var(--logo-scale, 1));
  object-fit: contain;
  /* Client logos keep their original brand colours at full strength (user
     decision, 2026-09-11); no dimming, no greyscale. */
  transition: transform 0.6s var(--ease);
}
.logo-cell:hover img { transform: scale(1.05); }
/* Square badge logos (logo_round: true in clients.yml) clipped to a circle. */
.logo-round img { border-radius: 50%; }

.metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2.5rem 1.25rem;
  margin-top: clamp(2.5rem, 5vw, 4rem);
}
@media (min-width: 900px) {
  .metrics { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 2rem; }
}
.metric {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding-left: 1.1rem;
  border-left: 1px solid var(--rule);
}
.metric::before {
  content: '';
  position: absolute;
  left: -1px;
  top: 0;
  width: 1px;
  height: 2.6rem;
  background: var(--accent);
}
.metric-num {
  order: -1;
  font-size: clamp(2.1rem, 4vw, 3.1rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.045em;
  white-space: nowrap;
}
.metric-label { font-size: 0.95rem; font-weight: 500; margin-top: 0.6rem; }
.metric-desc { font-size: 0.875rem; line-height: 1.5; color: var(--ink-3); max-width: 26ch; }

.motion .metric::before {
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 1.1s var(--ease);
  transition-delay: calc(300ms + var(--i) * 120ms);
}
.motion .metric.is-visible::before { transform: none; }

/* ==========================================================================
   Services: sticky index + detail cards
   ========================================================================== */

.services-grid { display: grid; gap: 2.5rem; }
@media (min-width: 960px) {
  .services-grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 4.5rem; align-items: start; }
  .services-aside { height: 100%; }
  .services-sticky { position: sticky; top: calc(var(--topbar-h) + 3rem); }
}

.services-index { display: none; flex-direction: column; margin-top: 2.5rem; }
@media (min-width: 960px) { .services-index { display: flex; } }
.services-index a {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding-block: 0.6rem;
  font-weight: 500;
  color: var(--ink-3);
  transition: color 0.35s ease;
}
.services-index a:hover { color: var(--ink-2); }
.idx-bar {
  width: 44px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0.4);
  transform-origin: left center;
  transition: transform 0.6s var(--ease), background-color 0.35s ease;
}
.services-index a.is-active { color: var(--ink); }
.services-index a.is-active .idx-bar { transform: none; background: var(--accent); }

.services-list { display: flex; flex-direction: column; gap: 1.25rem; }

.service {
  padding: clamp(1.5rem, 3.2vw, 2.4rem);
  border: 1px solid var(--rule);
  border-radius: var(--r-surface);
  background: var(--ground);
}
.service-icon { width: 30px; height: 30px; color: var(--accent); }
.service-title {
  margin-top: 1.4rem;
  font-size: clamp(1.3rem, 2vw, 1.55rem);
  font-weight: 600;
  letter-spacing: -0.025em;
}
.service-desc { margin-top: 0.6rem; color: var(--ink-2); max-width: 58ch; }

.deliverables {
  display: grid;
  gap: 0.7rem;
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
}
.deliverables li { display: flex; align-items: flex-start; gap: 0.7rem; font-size: 0.95rem; line-height: 1.5; }
.deliverables .ico { color: var(--accent); margin-top: 0.15rem; }

.tags { display: flex; flex-wrap: wrap; gap: 0.45rem; margin-top: 1.5rem; }
.tags li {
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--ink-2);
}

/* ==========================================================================
   Audiences: B2B / B2C panels
   ========================================================================== */

.aud-grid {
  display: grid;
  gap: 1.25rem;
  margin-top: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 900px) {
  .aud-grid { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
}

.aud {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-height: 360px;
  padding: clamp(1.75rem, 3.6vw, 2.75rem);
  border: 1px solid var(--rule);
  border-radius: var(--r-surface);
  background: var(--ground);
  overflow: hidden;
}
.aud p { color: var(--ink-2); max-width: 48ch; }
.aud-icon { width: 34px; height: 34px; color: var(--accent); margin-bottom: auto; }
.aud-title {
  margin-top: 2.5rem;
  font-size: clamp(1.4rem, 2.3vw, 1.85rem);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.03em;
}
.aud-tags { margin-top: 0.75rem; }

/* Ink panel: a faint measurement grid fades in from the top-right corner. */
.aud-dark {
  background-color: var(--ink-surface);
  background-image:
    linear-gradient(to right, var(--rule-on-dark) 1px, transparent 1px),
    linear-gradient(to bottom, var(--rule-on-dark) 1px, transparent 1px);
  background-size: 44px 44px;
  background-position: -1px -1px;
  border-color: var(--ink-surface);
  color: var(--on-dark);
}
.aud-dark::selection, .aud-dark *::selection { background: var(--accent-on-dark); color: var(--ink); }
.aud-dark > * { position: relative; }
.aud-dark::before {
  /* Overrides the spotlight wash: on ink it is a mask over the grid. */
  opacity: 1;
  background: radial-gradient(120% 90% at 100% 0%, transparent 0%, var(--ink-surface) 62%);
}
.aud-dark:hover::before {
  background:
    radial-gradient(360px circle at var(--mx, 50%) var(--my, 50%), rgb(143 180 214 / 0.12), transparent 60%),
    radial-gradient(120% 90% at 100% 0%, transparent 0%, var(--ink-surface) 62%);
}
.aud-dark::after { background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 50%), var(--accent-on-dark), transparent 60%); }
.aud-dark p { color: var(--on-dark-2); }
.aud-dark .aud-icon { color: var(--accent-on-dark); }
.aud-dark .tags li { border-color: var(--rule-on-dark); color: var(--on-dark-2); }

/* ==========================================================================
   Approach: signal chain
   ========================================================================== */

.chain { position: relative; }

.chain-track {
  position: absolute;
  left: 7px;
  top: 8px;
  bottom: 8px;
  width: 1px;
  background: var(--rule);
}
.chain-fill {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform-origin: top center;
}

.chain-steps { position: relative; display: grid; gap: 2.75rem; }
.chain-step { position: relative; padding-left: 2.5rem; }

@media (min-width: 960px) {
  .chain-track { left: 0; right: 0; top: 7px; bottom: auto; width: auto; height: 1px; }
  .chain-fill { transform-origin: left center; }
  .chain-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2rem; }
  .chain-step { padding-left: 0; padding-top: 2.5rem; padding-right: 0.5rem; }
}

.chain-node {
  position: absolute;
  left: 0;
  top: 0;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 5px var(--accent-ring);
}
.chain-phase {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.chain-title {
  margin-top: 0.5rem;
  font-size: 1.15rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.015em;
}
.chain-desc { margin-top: 0.5rem; font-size: 0.95rem; line-height: 1.6; color: var(--ink-2); }
.chain-out {
  display: inline-block;
  margin-top: 1.1rem;
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--ink-2);
}

/* Choreography: the line draws, then each node lights as the line reaches it
   and its copy rises in behind it. */
.motion .chain-fill { transform: scaleY(0); transition: transform 2.2s var(--ease-io) 0.1s; }
@media (min-width: 960px) {
  .motion .chain-fill { transform: scaleX(0); }
}
.motion .chain.is-live .chain-fill { transform: none; }

.motion .chain-node {
  background: var(--ground);
  box-shadow: inset 0 0 0 1px var(--rule-strong), 0 0 0 0 var(--accent-ring);
  transition: background-color 0.4s ease, box-shadow 0.6s var(--ease);
  transition-delay: calc(150ms + var(--i) * 520ms);
}
.motion .chain.is-live .chain-node {
  background: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 5px var(--accent-ring);
}
.motion .chain-step > :not(.chain-node) {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.7s ease, transform 0.9s var(--ease);
  transition-delay: calc(250ms + var(--i) * 520ms);
}
.motion .chain.is-live .chain-step > :not(.chain-node) { opacity: 1; transform: none; }

/* ==========================================================================
   Why us: bento
   ========================================================================== */

.bento { display: grid; gap: 1.25rem; }
@media (min-width: 768px) {
  .bento { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .bento-1, .bento-4 { grid-column: span 7; }
  .bento-2, .bento-3 { grid-column: span 5; }
}

.bento-cell {
  display: flex;
  flex-direction: column;
  min-height: 280px;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border: 1px solid var(--rule);
  border-radius: var(--r-surface);
  background: var(--ground);
  overflow: hidden;
}
.bento-cell > :not(.cell-art) { position: relative; }
.cell-icon { width: 30px; height: 30px; color: var(--accent); }
.cell-title {
  margin-top: auto;
  padding-top: 3.5rem;
  font-size: clamp(1.2rem, 1.9vw, 1.4rem);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.02em;
}
.cell-desc { margin-top: 0.5rem; color: var(--ink-2); max-width: 46ch; }

.cell-art { position: absolute; inset: 0; pointer-events: none; }

/* Cell 1: dot matrix, fading out towards the copy. */
.bento-1 .cell-art {
  background-image: radial-gradient(rgb(16 69 122 / 0.2) 1.2px, transparent 1.3px);
  background-size: 16px 16px;
  -webkit-mask-image: radial-gradient(90% 90% at 100% 0%, #000 10%, transparent 70%);
  mask-image: radial-gradient(90% 90% at 100% 0%, #000 10%, transparent 70%);
}
/* Cell 3: navy tint washing down from the top. */
.bento-3 { background: linear-gradient(170deg, var(--accent-tint) 0%, var(--ground) 65%); }

/* Cell 4: ink feature cell. */
.bento-4 {
  background: var(--ink-surface);
  border-color: var(--ink-surface);
  color: var(--on-dark);
}
.bento-4 .cell-art {
  background-image:
    linear-gradient(to right, var(--rule-on-dark) 1px, transparent 1px),
    linear-gradient(to bottom, var(--rule-on-dark) 1px, transparent 1px);
  background-size: 40px 40px;
  -webkit-mask-image: radial-gradient(80% 100% at 100% 0%, #000 0%, transparent 70%);
  mask-image: radial-gradient(80% 100% at 100% 0%, #000 0%, transparent 70%);
}
.bento-4 .cell-icon { color: var(--accent-on-dark); }
.bento-4 .cell-desc { color: var(--on-dark-2); }
.bento-4::before { background: radial-gradient(360px circle at var(--mx, 50%) var(--my, 50%), rgb(143 180 214 / 0.12), transparent 60%); }
.bento-4::after { background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 50%), var(--accent-on-dark), transparent 60%); }

.bento-cell .cell-icon { transition: transform 0.6s var(--ease); }
.bento-cell:hover .cell-icon { transform: translateY(-3px) rotate(-6deg); }

/* ==========================================================================
   Testimonials
   ========================================================================== */

.tm-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}
.tm-nav { display: flex; gap: 0.5rem; flex: none; }
.tm-nav[hidden] { display: none; }

.tm-rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 86%;
  gap: 1.25rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding: 2px;
  margin: -2px;
}
.tm-rail::-webkit-scrollbar { display: none; }
@media (min-width: 768px) { .tm-rail { grid-auto-columns: calc((100% - 1.25rem) / 2); } }
@media (min-width: 1100px) { .tm-rail { grid-auto-columns: calc((100% - 2.5rem) / 3); } }

.tm-slide { display: flex; scroll-snap-align: start; }

/* Scroll position: thumb length is the visible share of the rail, so it
   shortens as testimonials are added. Hidden while everything fits. */
.tm-progress {
  position: relative;
  height: 2px;
  margin-top: 1.75rem;
  background: var(--rule);
  overflow: hidden;
}
.tm-progress[hidden] { display: none; }
.tm-progress-thumb {
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform-origin: left center;
}

.tm-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: clamp(1.5rem, 3vw, 2rem);
  border: 1px solid var(--rule);
  border-radius: var(--r-surface);
  background: var(--ground);
}
.tm-mark {
  display: block;
  height: 2rem;
  font-size: 3.5rem;
  font-weight: 600;
  line-height: 1;
  color: var(--accent);
}
.tm-quote p { font-size: 1.02rem; line-height: 1.65; }
.tm-quote p + p { margin-top: 1rem; }

.tm-more {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  align-self: flex-start;
  margin-top: 1rem;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--accent);
}
.tm-more .ico { transition: transform 0.45s var(--ease); }
.tm-more:hover .ico { transform: translateX(3px); }

.tm-cite {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin-top: auto;
  padding-top: 1.5rem;
}
.tm-card .tm-cite { margin-top: auto; }
.tm-card > .tm-cite { padding-top: 1.5rem; }
.tm-card > .tm-cite::before {
  content: '';
  display: block;
  height: 1px;
  margin-bottom: 1.25rem;
  background: var(--rule);
}
.tm-cite-head { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; }
.tm-linkedin { display: inline-flex; color: var(--ink-3); transition: color 0.25s ease; }
.tm-linkedin:hover { color: var(--accent); }
.tm-linkedin .ico { width: 16px; height: 16px; }
.tm-cite-role { font-size: 0.875rem; color: var(--ink-3); }

.tm-modal {
  width: min(640px, calc(100% - 2rem));
  max-height: calc(100dvh - 2rem);
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border: 0;
  border-radius: var(--r-surface);
  background: var(--ground);
  box-shadow: var(--lift);
  overflow: auto;
}
.tm-modal::backdrop { background: rgb(14 17 22 / 0.42); }
.tm-modal-close { position: absolute; top: 1rem; right: 1rem; }
.tm-modal-body .tm-cite { padding-top: 1.5rem; margin-top: 1.5rem; border-top: 1px solid var(--rule); }
.motion .tm-modal[open] { animation: modal-in 0.5s var(--ease); }
.motion .tm-modal[open]::backdrop { animation: fade 0.4s ease; }
@keyframes modal-in { from { opacity: 0; transform: translateY(16px) scale(0.98); } }

/* ==========================================================================
   Contact
   ========================================================================== */

.contact { border-top: 1px solid var(--rule); }
.contact-grid { display: grid; gap: 3rem; }
@media (min-width: 960px) {
  .contact-grid { grid-template-columns: minmax(0, 7fr) minmax(0, 4fr); gap: 4.5rem; align-items: end; }
}

.contact-title {
  font-size: clamp(2.6rem, 6.4vw, 5.25rem);
  font-weight: 600;
  line-height: 0.98;
  letter-spacing: -0.05em;
  max-width: 12ch;
  text-wrap: balance;
}

.channels { margin-top: clamp(2rem, 4vw, 3rem); }
.channel {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding-block: 1.25rem;
  border-top: 1px solid var(--rule);
}
.channel-label { font-family: var(--font-mono); font-size: 0.75rem; color: var(--ink-3); }
/* The email plus its copy button must share a row down to 360px wide, so
   the address may drop to 0.95rem on small phones; narrower still, the
   button wraps under it. */
.channel-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.channel-value {
  font-size: clamp(0.95rem, 4.2vw, 1.9rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  overflow-wrap: anywhere;
  background: linear-gradient(var(--accent), var(--accent)) left bottom / 0% 1px no-repeat;
  transition: color 0.3s ease, background-size 0.6s var(--ease);
}
.channel-value:hover { color: var(--accent); background-size: 100% 1px; }

.copy-btn .ico { grid-area: 1 / 1; transition: opacity 0.25s ease, transform 0.45s var(--ease); }
.copy-btn .ico-done { opacity: 0; transform: scale(0.6); }
.copy-btn.is-copied { background: var(--accent); color: #fff; box-shadow: inset 0 0 0 1px var(--accent); }
.copy-btn.is-copied .ico-copy { opacity: 0; transform: scale(0.6); }
.copy-btn.is-copied .ico-done { opacity: 1; transform: none; }

.contact-rail {
  padding: clamp(1.5rem, 3vw, 2rem);
  border: 1px solid var(--rule);
  border-radius: var(--r-surface);
}
.rail-title { font-size: 1rem; font-weight: 600; letter-spacing: -0.01em; }
.rail-list { display: grid; gap: 0.85rem; margin-top: 1.25rem; }
.rail-list li { display: flex; align-items: flex-start; gap: 0.7rem; font-size: 0.95rem; line-height: 1.5; color: var(--ink-2); }
.rail-list .ico { color: var(--accent); margin-top: 0.15rem; }

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  padding-top: clamp(3.5rem, 6vw, 5rem);
  border-top: 1px solid var(--rule);
  overflow: hidden;
}
.footer-grid { display: grid; gap: 2.5rem; }
@media (min-width: 768px) {
  .footer-grid { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
}
.footer-tagline { margin-top: 1rem; max-width: 36ch; color: var(--ink-2); }

.footer-links { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2rem; }
.footer-group { display: flex; flex-direction: column; align-items: flex-start; }
.footer-group-title { margin-bottom: 0.75rem; font-size: 0.8rem; font-weight: 500; color: var(--ink-3); }
.footer-group a {
  padding-block: 0.3rem;
  color: var(--ink-2);
  background: linear-gradient(currentColor, currentColor) left 85% / 0% 1px no-repeat;
  transition: color 0.25s ease, background-size 0.5s var(--ease);
}
.footer-group a:hover { color: var(--ink); background-size: 100% 1px; }

.footer-bottom {
  margin-top: 3.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  font-size: 0.85rem;
  color: var(--ink-3);
}

.footer-word {
  display: flex;
  justify-content: center;
  margin-top: 2rem;
  font-size: clamp(3rem, 12.2vw, 10.5rem);
  font-weight: 600;
  line-height: 0.8;
  letter-spacing: -0.06em;
  white-space: nowrap;
  color: #eceff3;
  user-select: none;
  overflow: hidden;
  padding-top: 0.08em;
}
.footer-word span { display: inline-block; }
.motion .footer-word span {
  transform: translateY(105%);
  transition: transform 1.2s var(--ease);
  transition-delay: calc(var(--i) * 40ms);
}
.motion .footer-word.is-visible span { transform: none; }

/* ==========================================================================
   Touch targets
   Standalone text links and icon links get a hit area of about 44px without
   changing how they look: padding grows the target, and a matching negative
   margin keeps the layout where it was.
   ========================================================================== */

.brand { min-height: 44px; }
.tm-more { min-height: 44px; margin-block: 0.25rem -0.5rem; }
.tm-linkedin { padding: 14px 14px 14px 8px; margin: -14px -14px -14px -8px; }
.channel-value { display: inline-block; padding-block: 0.5rem; margin-block: -0.5rem; }
@media (max-width: 767px) {
  .footer-group a { padding-block: 0.6rem; }
}
