/* Paws Trend — light product-led landing.
   Independent of assets/css/style.css (dark), which the other pages still use.
   Tokens only below this block: no raw hex in components. */

:root {
  /* surface */
  --bg: #eff0f2;
  --surface: #ffffff;
  --surface-sunken: #f6f7f8;
  --line: rgba(0, 0, 0, 0.08);
  --line-strong: rgba(0, 0, 0, 0.14);

  /* ink */
  --text: #0a0a0b;
  /* Same hue/saturation as the old #6b7280, two steps darker. #6b7280 only made
     4.24:1 on --bg, so body copy failed WCAG AA. This clears 4.5:1 on all three
     light surfaces: 4.76 on --bg, 5.43 on --surface, 5.06 on --surface-sunken. */
  --text-dim: #646a77;
  --ink: #0a0a0b;
  --on-ink: #ffffff;
  --on-ink-dim: rgba(255, 255, 255, 0.62);

  /* accent — one blue. Red only terminates the gradient. */
  --blue: #2f8fd6;
  --blue-soft: rgba(47, 143, 214, 0.10);
  --red: #ff4d4d;
  --gradient: linear-gradient(135deg, var(--blue), var(--red));

  /* pastel chips */
  --chip-green: rgba(52, 168, 83, 0.12);
  --chip-pink: rgba(236, 72, 153, 0.12);
  --chip-purple: rgba(139, 92, 246, 0.12);
  --chip-blue: rgba(47, 143, 214, 0.12);

  /* app-window stage — near-opaque on purpose: the 3D objects were lit for a
     white room and lose contrast if an aurora blob shows through behind them. */
  --surface-stage: rgba(255, 255, 255, 0.92);

  /* ── aurora ──────────────────────────────────────────────────────────────
     Three colour fields drift behind the whole page. The hues are ones the
     system already owns: --blue, the --chip-purple violet, and --red. The veil
     is a fixed white wash painted over all three — it is the contrast floor,
     not a styling choice, and must never be animated or removed. Red rides
     lower than the other two because saturated red reads heavier at equal
     alpha and drags the page toward "warning banner". */
  --aurora-1: rgba(47, 143, 214, 0.45);
  --aurora-2: rgba(139, 92, 246, 0.42);
  --aurora-3: rgba(255, 77, 77, 0.34);
  --aurora-veil: rgba(255, 255, 255, 0.34);
  --aurora-blur: 60px;
  --aurora-blur-sm: 36px;

  /* ── glass ───────────────────────────────────────────────────────────────
     --glass-bg's 0.78 is a contrast floor, not a taste call. The darkest pixel
     the aurora can produce is #b8bbf3 (blue+violet at peak alpha, then the
     veil); saturate(150%) takes it to #b4baff; 78% white over that lands on
     #eff0ff, where --text-dim scores 4.79:1. At 0.65 it would be ~4.3:1 and
     fail AA. Do not lower it without redoing that arithmetic.
     --glass-mask exists so the rim highlight's mask can be written without a
     raw hex below :root. */
  --glass-bg: rgba(255, 255, 255, 0.78);
  --glass-bg-solid: rgba(255, 255, 255, 0.88);
  --glass-bg-nav: rgba(255, 255, 255, 0.72);
  --glass-border: rgba(255, 255, 255, 0.60);
  --glass-rim: rgba(255, 255, 255, 0.90);
  --glass-rim-soft: rgba(255, 255, 255, 0.35);
  --glass-clear: rgba(255, 255, 255, 0);
  --glass-mask: linear-gradient(rgba(0, 0, 0, 1) 0 0);
  --glass-blur: 20px;
  --glass-blur-card: 12px;
  --glass-blur-nav: 14px;
  --glass-blur-nav-lg: 22px;
  --glass-saturate: 150%;
  --glass-saturate-nav: 180%;
  --glass-shadow: 0 1px 2px rgba(0, 0, 0, 0.04),
                  0 12px 32px rgba(16, 24, 48, 0.08),
                  0 32px 64px rgba(16, 24, 48, 0.05);
  --glass-shadow-lift: 0 2px 6px rgba(0, 0, 0, 0.05),
                       0 20px 48px rgba(16, 24, 48, 0.12);
  --shadow-ink: 0 40px 80px -24px rgba(16, 24, 48, 0.35);

  /* ── per-service identity ────────────────────────────────────────────────
     Three of the five hues already exist in the chip palette, so this reads as
     an extension of the system rather than five invented colours.
     --svc-*      vivid: glows, fills, 3D accents.
     --svc-*-ink  darkened text form. ALWAYS use this for text — the vivid
                  values are 2.1–3.5:1 on white and would fail AA. Each -ink
                  below clears 4.5:1 on the worst possible glass surface
                  (#eff0ff), on white, and on its own -soft pill. */
  --svc-build: #2f8fd6;
  --svc-build-ink: #1a5f8c;
  --svc-build-soft: rgba(47, 143, 214, 0.12);
  --svc-build-glow: rgba(47, 143, 214, 0.28);

  --svc-intelligence: #8b5cf6;
  --svc-intelligence-ink: #6d3fd4;
  --svc-intelligence-soft: rgba(139, 92, 246, 0.12);
  --svc-intelligence-glow: rgba(139, 92, 246, 0.28);

  --svc-content: #ec4899;
  --svc-content-ink: #b52568;
  --svc-content-soft: rgba(236, 72, 153, 0.12);
  --svc-content-glow: rgba(236, 72, 153, 0.28);

  --svc-growth: #f59e0b;
  --svc-growth-ink: #8a5502;
  --svc-growth-soft: rgba(245, 158, 11, 0.12);
  --svc-growth-glow: rgba(245, 158, 11, 0.28);

  --svc-foundation: #14b8a6;
  --svc-foundation-ink: #0b7067;
  --svc-foundation-soft: rgba(20, 184, 166, 0.12);
  --svc-foundation-glow: rgba(20, 184, 166, 0.28);

  /* Current-service channel, rebound by [data-service] on .showcase. These
     defaults are what the no-JS page renders. */
  --svc: var(--svc-build);
  --svc-ink: var(--svc-build-ink);
  --svc-soft: var(--svc-build-soft);
  --svc-glow: var(--svc-build-glow);

  /* type */
  --font: 'Inter', system-ui, -apple-system, sans-serif;

  /* spacing — same scale as the dark system */
  --space-1: 1px;  --space-2: 4px;  --space-3: 8px;  --space-4: 15px;
  --space-5: 28px; --space-6: 40px; --space-7: 48px; --space-8: 56px;
  --space-9: 88px; --space-10: 128px;

  /* radius */
  --radius-shell: 40px;
  --radius-card: 32px;
  --radius-window: 20px;
  --radius-sm: 12px;
  --radius-pill: 9999px;

  /* depth — structural, never decorative. No colored glows. */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.04);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.05), 0 16px 40px rgba(0, 0, 0, 0.07);

  /* motion */
  --transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-slow: 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

/* ── Reset ──────────────────────────────────────────────────────────────── */

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

body,
h1, h2, h3, h4, h5, h6,
p,
figure,
blockquote,
ul, ol, dl, dd {
  margin: 0;
}

img,
svg,
video {
  max-width: 100%;
}

img {
  display: block;
  height: auto;
}

/* ── Base ───────────────────────────────────────────────────────────────── */

body {
  background: var(--bg);
  color: var(--text-dim);
  font-family: var(--font);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Cards and pinned sections overshoot the viewport during motion; never let
     that turn into a horizontal scrollbar. */
  overflow-x: hidden;
}

/* ── Aurora background ──────────────────────────────────────────────────── */

.aurora {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  /* Isolates this layer's paint and layout from the page. NOT `contain: strict`
     — that includes size containment, which would collapse an inset:0 box. */
  contain: layout paint style;
}

/* Explicit stacking rather than relying on negative z-index against the body's
   propagated background. */
main,
.footer {
  position: relative;
  z-index: 1;
}

/* The blob's gradient, blur and drift all live on ::before, and the parallax
   in motion.js writes transform on the parent. This split is load-bearing: a
   CSS @keyframes animation sits ABOVE the inline-style cascade origin, so a
   drift animation on the same element GSAP writes to would silently win and
   the parallax would look broken with no error anywhere. */
.aurora-blob {
  position: absolute;
  will-change: transform;
}

.aurora-blob::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  /* A radial gradient fading to transparent is already soft; the blur only
     dissolves the banding a field this large shows on 8-bit displays. It is
     rasterised once and then only composited — which is why nothing here ever
     animates the blur radius, the gradient stops, or opacity. */
  filter: blur(var(--aurora-blur));
  will-change: transform;
}

.aurora-blob--1 { width: 72vmax; height: 72vmax; top: -20vmax; left: -16vmax; }
.aurora-blob--2 { width: 64vmax; height: 64vmax; top: 6vmax; right: -18vmax; }
.aurora-blob--3 { width: 56vmax; height: 56vmax; bottom: -22vmax; left: 20vmax; }

.aurora-blob--1::before {
  background: radial-gradient(circle at 50% 50%, var(--aurora-1) 0%, var(--glass-clear) 68%);
  animation: aurora-drift-1 34s ease-in-out infinite alternate;
}

.aurora-blob--2::before {
  background: radial-gradient(circle at 50% 50%, var(--aurora-2) 0%, var(--glass-clear) 68%);
  animation: aurora-drift-2 42s ease-in-out infinite alternate;
}

.aurora-blob--3::before {
  background: radial-gradient(circle at 50% 50%, var(--aurora-3) 0%, var(--glass-clear) 68%);
  animation: aurora-drift-3 28s ease-in-out infinite alternate;
}

/* Three durations that don't share a common factor, so the composite never
   visibly loops. */
@keyframes aurora-drift-1 {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(6vmax, 4vmax, 0) scale(1.12); }
}

@keyframes aurora-drift-2 {
  from { transform: translate3d(0, 0, 0) scale(1.08); }
  to   { transform: translate3d(-7vmax, 5vmax, 0) scale(1); }
}

@keyframes aurora-drift-3 {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(5vmax, -6vmax, 0) scale(1.15); }
}

/* The contrast floor. Fixed opacity, painted over all three blobs, never
   animated, never conditional — this is what makes the glass surfaces above
   it provably clear 4.5:1 no matter where the blobs have drifted to. */
.aurora::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--aurora-veil);
  pointer-events: none;
}

h1, h2, h3 {
  color: var(--text);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.05;
}

/* ── Display type ───────────────────────────────────────────────────────── */

.display-1 { font-size: clamp(40px, 6vw, 76px); font-weight: 800; letter-spacing: -0.045em; }
.display-2 { font-size: clamp(28px, 4vw, 44px); font-weight: 800; letter-spacing: -0.045em; }

.lede {
  max-width: 46ch;
  color: var(--text-dim);
  font-size: clamp(17px, 1.4vw, 19px);
}

/* The blue→red gradient is rationed to exactly two words on the page: the hero
   focal word and the CTA headline focal word. Nowhere else. */
.gradient-word {
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ── Pill badge ─────────────────────────────────────────────────────────── */

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
  background: var(--glass-bg-solid);
  box-shadow: var(--shadow-sm);
  color: var(--text);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
}

/* ── Buttons ────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-3) var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-family: inherit;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--transition), box-shadow var(--transition),
              border-color var(--transition), background var(--transition);
}

.btn--primary {
  background: var(--ink);
  color: var(--on-ink);
}

.btn--ghost {
  background: var(--glass-bg-solid);
  border-color: var(--glass-border);
  color: var(--text);
}

.btn--primary:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lift);
}

.btn--ghost:hover {
  border-color: var(--line-strong);
}

.btn:active {
  transform: none;
  box-shadow: none;
}

.btn:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 3px;
}

/* ── Glass surfaces ─────────────────────────────────────────────────────────
   .glass        translucent + backdrop blur. For surfaces sitting directly on
                 the aurora.
   .glass-solid  the same look with no backdrop-filter. For surfaces NESTED
                 inside a .glass surface — stacking blurs on the same pixels is
                 the expensive case and, over a smooth gradient, is visually a
                 no-op.
   Budget: at most 5 backdrop-filtered surfaces per viewport, never nested,
   never above 20px. Worst case here is nav + four .step cards. */

.glass,
.glass-solid {
  position: relative;
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
}

.glass { background: var(--glass-bg); }
.glass-solid { background: var(--glass-bg-solid); }

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass {
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
            backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  }
}

/* Inner rim highlight: a 1px gradient border, bright on the top-left edge,
   fading out through the middle, a fainter return bottom-right. This is the
   detail that separates "translucent div" from "glass". Drawn as a masked
   pseudo-element because a border cannot hold a gradient. */
.glass::before,
.glass-solid::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(145deg,
    var(--glass-rim) 0%,
    var(--glass-clear) 42%,
    var(--glass-clear) 58%,
    var(--glass-rim-soft) 100%);
  -webkit-mask: var(--glass-mask) content-box, var(--glass-mask);
  -webkit-mask-composite: xor;
          mask: var(--glass-mask) content-box, var(--glass-mask);
          mask-composite: exclude;
  pointer-events: none;
}

/* Without mask compositing the rim paints as a full-surface gradient wash over
   the card's own content, which is much worse than simply not having a rim. */
@supports not ((mask-composite: exclude) or (-webkit-mask-composite: xor)) {
  .glass::before,
  .glass-solid::before { display: none; }
}

/* ── Glass hover: tilt, lift, coloured glow, cursor sheen ───────────────────
   --tilt-x/--tilt-y/--tilt-scale/--lift/--pointer-x/--pointer-y are written by
   assets/js/studio/tilt.js on pointermove (full tier only). Every one has an
   inline fallback here, so with no JS the transform is an exact no-op and the
   plain :hover lift below still works at every tier. */

.glass-hover {
  /* Default glow is the `build` service's — correct for .step/.stat (which
     carry no data-service) and for the no-JS default state of the tabs. The
     inline fallback is a defensive no-op now that --svc-build-glow is a real
     token (Task 2): kept in case a future .glass-hover surface ever mounts
     before :root finishes parsing in some exotic loading order. */
  --glow: var(--svc-build-glow, rgba(47, 143, 214, 0.28));
  --glow-solid: var(--svc-build, #2f8fd6);
  transform: perspective(900px)
             translateY(var(--lift, 0px))
             rotateX(var(--tilt-x, 0deg))
             rotateY(var(--tilt-y, 0deg))
             scale(var(--tilt-scale, 1));
  transform-style: preserve-3d;
  transition: transform var(--transition), box-shadow var(--transition),
              background var(--transition), color var(--transition);
}

.glass-hover:hover {
  --lift: -6px;
  background: var(--glass-bg-solid);
  /* Solid 2px accent edge, not another soft glow — the one deliberately hard
     cut borrowed from the kinetic reference. Everything else here still eases
     over --transition; this line has no separate timing of its own, so it
     rides the same box-shadow transition as the glow instead of snapping
     independently (a true instant cut looked like a flicker next to the
     eased lift). */
  box-shadow: var(--glass-shadow-lift),
              0 0 0 2px var(--glow-solid),
              0 18px 48px -12px var(--glow);
}

/* Cursor-following sheen — one small repaint on one element, the cheapest
   possible "this card is reacting to me". */
.glass-hover::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background: radial-gradient(220px circle at var(--pointer-x, 50%) var(--pointer-y, 50%),
                              var(--glow), var(--glass-clear) 72%);
  opacity: 0;
  transition: opacity var(--transition);
  pointer-events: none;
}

.glass-hover:hover::after { opacity: 0.55; }

/* Card content must clear both pseudo-elements. */
.step > *,
.stat > * {
  position: relative;
  z-index: 1;
}

/* ── Section shell ──────────────────────────────────────────────────────── */

.section {
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--space-10) var(--space-5);
}

@media (max-width: 767px) {
  .section {
    padding-top: var(--space-9);
    padding-bottom: var(--space-9);
  }
}

/* ── Chips ──────────────────────────────────────────────────────────────── */

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.4;
  /* Softened ink rather than element opacity, which would also wash out the
     pastel fill behind it. */
  color: var(--text);
}

/* The usual two-declaration fallback doesn't work for color-mix here: the value
   contains var(), so it parses as valid regardless of support, wins the cascade,
   and then fails at computed-value time — leaving `color` inherited rather than
   falling back. @supports is the only form that actually degrades. */
@supports (color: color-mix(in srgb, red 50%, transparent)) {
  .chip { color: color-mix(in srgb, var(--text) 72%, transparent); }
}

.chip--green  { background: var(--chip-green); }
.chip--pink   { background: var(--chip-pink); }
.chip--purple { background: var(--chip-purple); }
.chip--blue   { background: var(--chip-blue); }

/* ── Motion preference ──────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: none;
  }

  .btn--primary:hover {
    transform: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTIONS — the landing page. Everything below composes the primitives above;
   no new colors, no raw hex, no spacing outside the --space-* scale.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Shared: focus, links ───────────────────────────────────────────────── */

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 3px;
}

/* Centered display type strands single words on the last line at narrow widths.
   Ignored where unsupported, so it is pure upside. */
.hero h1,
.hero .lede,
.process h2,
.proof h2,
.about p,
.cta h2 {
  text-wrap: balance;
}

/* Arrow links. One shape for the tab panels and the about teaser so the page
   only ever teaches the reader a single "go deeper" affordance. */
.panel-link,
.text-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  /* was var(--blue) — 3.49:1 on white, below AA. --svc-ink is the accessible
     form and inside the showcase it also tracks the active service. */
  color: var(--svc-ink);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
}

.panel-link svg,
.text-link svg {
  transition: transform var(--transition);
}

.panel-link:hover,
.text-link:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.panel-link:hover svg,
.text-link:hover svg {
  transform: translateX(3px);
}

/* ── Nav ────────────────────────────────────────────────────────────────── */

.navbar {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 100;
  border-bottom: 1px solid var(--glass-border);
  /* Opaque fallback first; translucency only where backdrop-filter parses, so
     the bar is never unreadable. */
  background: var(--surface);
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .navbar {
    background: var(--glass-bg-nav);
    -webkit-backdrop-filter: blur(var(--glass-blur-nav)) saturate(140%);
            backdrop-filter: blur(var(--glass-blur-nav)) saturate(140%);
  }

  /* Scroll state (class toggled by index.js): the blur and saturation both
     step up, so the bar reads as denser glass over the moving aurora. */
  .navbar.is-scrolled {
    -webkit-backdrop-filter: blur(var(--glass-blur-nav-lg)) saturate(var(--glass-saturate-nav));
            backdrop-filter: blur(var(--glass-blur-nav-lg)) saturate(var(--glass-saturate-nav));
  }
}

.navbar.is-scrolled {
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition), backdrop-filter var(--transition);
}

.navbar .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--space-4) var(--space-5);
  transition: padding var(--transition);
}

.navbar.is-scrolled .container {
  padding-top: var(--space-3);
  padding-bottom: var(--space-3);
}

.navbar .logo {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
}

.navbar .logo img {
  width: auto;
  height: 42px;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-links > li {
  flex: 0 0 auto;
}

.nav-links a {
  color: var(--text-dim);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--transition);
}

.nav-links a:hover {
  color: var(--text);
}

/* The shared nav markup uses the dark stylesheet's `.btn-primary` (single dash),
   not this system's `.btn--primary`. Style it here rather than edit the markup,
   which the other eight pages also render. */
.nav-links .btn-primary {
  min-height: 40px;
  padding: var(--space-3) var(--space-5);
  background: var(--ink);
  color: var(--on-ink);
}

.nav-links .btn-primary:hover {
  color: var(--on-ink);
  transform: translateY(-1px);
  box-shadow: var(--shadow-lift);
}

/* Services dropdown. Opacity + pointer-events rather than visibility/display so
   the links stay in the tab order — tabbing into one fires :focus-within, which
   reveals the menu. visibility:hidden would make :focus-within unreachable. */
.nav-dropdown {
  position: relative;
}

/* The 15px offset below is margin, which is dead space: moving the cursor
   from the parent link down toward the menu crossed unhoverable ground, the
   :hover on .nav-dropdown dropped, and the menu vanished mid-approach. The
   ::before bridge below covers exactly that gap and belongs to the menu, so
   the pointer never leaves the dropdown while travelling to it. */
.nav-dropdown-menu {
  position: absolute;
  top: 100%;
  left: 50%;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 250px;
  margin-top: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  background: var(--glass-bg-solid);
  box-shadow: var(--shadow-card);
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(-4px);
  transition: opacity var(--transition), transform var(--transition);
}

/* Invisible hover bridge across the margin gap. Inherits the menu's own
   pointer-events, so it is inert while the menu is closed. */
.nav-dropdown-menu::before {
  content: '';
  position: absolute;
  right: 0;
  bottom: 100%;
  left: 0;
  height: var(--space-4);
}

.nav-dropdown-menu a {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  transition: background var(--transition), color var(--transition);
}

.nav-dropdown-menu a:hover {
  background: var(--surface-sunken);
}

.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}

/* The hamburger's toggle lives in assets/js/main.js, which this page does not
   load. Rather than ship a dead control it is hidden at every width, and the nav
   links themselves scroll on narrow screens. */
.navbar .hamburger {
  display: none;
}

/* ── §1 Hero ────────────────────────────────────────────────────────────── */

.hero {
  /* The shell card below is wider than the shared .section column, so this
     section opts out of the 1200px cap and becomes the grey gutter instead. */
  max-width: none;
  /* Clears the fixed nav (~72px) and still leaves the badge real air above it. */
  padding-top: calc(var(--space-10) + var(--space-6));
  padding-bottom: var(--space-9);
  text-align: center;
}

.hero .pill {
  margin-bottom: var(--space-5);
}

.hero h1 {
  margin-bottom: var(--space-5);
}

.hero .lede {
  margin: 0 auto var(--space-6);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-4);
  margin-bottom: var(--space-9);
}

/* The reference's single giant card: everything above the app window plus the
   window itself lives inside one white shell, inset from the viewport edge by
   the grey .hero gutter around it. */
.hero-shell {
  position: relative;
  max-width: 1360px;
  margin: 0 auto;
  padding: var(--space-8) var(--space-7);
  border-radius: var(--radius-shell);
}

/* Cursor glow trail: assets/js/studio/hero-glow.js writes --glow-x/--glow-y
   (lagged, not 1:1 with the pointer — that lag is the "trail") and toggles
   --glow-opacity on enter/leave. Full tier only; the opacity default of 0
   makes this an exact no-op everywhere else, same contract as tilt.js. Direct
   children get z-index: 1 so the blob — and .glass's own ::before rim, which
   this sits above in paint order — never show through the content. */
.hero-shell > * {
  position: relative;
  z-index: 1;
}

.hero-shell::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background: radial-gradient(480px circle at var(--glow-x, 50%) var(--glow-y, 50%),
                               var(--svc-build-glow, rgba(47, 143, 214, 0.28)),
                               transparent 70%);
  opacity: var(--glow-opacity, 0);
  transition: opacity 0.4s ease;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .hero-shell::after {
    display: none;
  }
}

/* ── §2 Showcase ────────────────────────────────────────────────────────── */

.showcase {
  position: relative;
  padding: var(--space-5);
  text-align: left;
}

.showcase-tabs {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
  padding: var(--space-2);
  border-radius: var(--radius-pill);
  /* No visible track behind the row — the reference's tab row is plain; only
     the active tab gets a filled pill (below). */
  /* Tabs never shrink or wrap: when the five labels outgrow the track it scrolls
     inside its own box, so the page never gains a horizontal scrollbar. */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.showcase-tabs::-webkit-scrollbar {
  display: none;
}

.tab {
  position: relative;
  display: inline-flex;
  flex: 1 0 auto;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-3) var(--space-4);
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--transition), color var(--transition),
              transform var(--transition), box-shadow var(--transition);
}

.tab-icon {
  flex: 0 0 auto;
}

.tab:hover {
  background: var(--surface-sunken);
  color: var(--text);
}

/* Fallback fill for a tab that somehow lacks data-service — the per-service
   rules below are more specific and win whenever data-service is present. */
.tab[aria-selected="true"],
.tab[aria-selected="true"]:hover {
  background: var(--blue-soft);
  color: var(--blue);
}

.tab:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: -2px;
}

/* Each tab carries its own hue from a static attribute, so the active colour
   is correct with JavaScript disabled and needs no JS at all. */
.tab[data-service="build"]        { --glow: var(--svc-build-glow); }
.tab[data-service="intelligence"] { --glow: var(--svc-intelligence-glow); }
.tab[data-service="content"]      { --glow: var(--svc-content-glow); }
.tab[data-service="growth"]       { --glow: var(--svc-growth-glow); }
.tab[data-service="foundation"]   { --glow: var(--svc-foundation-glow); }

.tab[data-service="build"][aria-selected="true"],
.tab[data-service="build"][aria-selected="true"]:hover {
  background: var(--svc-build-soft);
  color: var(--svc-build-ink);
}

.tab[data-service="intelligence"][aria-selected="true"],
.tab[data-service="intelligence"][aria-selected="true"]:hover {
  background: var(--svc-intelligence-soft);
  color: var(--svc-intelligence-ink);
}

.tab[data-service="content"][aria-selected="true"],
.tab[data-service="content"][aria-selected="true"]:hover {
  background: var(--svc-content-soft);
  color: var(--svc-content-ink);
}

.tab[data-service="growth"][aria-selected="true"],
.tab[data-service="growth"][aria-selected="true"]:hover {
  background: var(--svc-growth-soft);
  color: var(--svc-growth-ink);
}

.tab[data-service="foundation"][aria-selected="true"],
.tab[data-service="foundation"][aria-selected="true"]:hover {
  background: var(--svc-foundation-soft);
  color: var(--svc-foundation-ink);
}

/* The showcase rebinds the whole current-service channel, so everything inside
   it — glow, rim tint, panel link — follows the active service. */
.showcase[data-service="build"] {
  --svc: var(--svc-build); --svc-ink: var(--svc-build-ink);
  --svc-soft: var(--svc-build-soft); --svc-glow: var(--svc-build-glow);
}
.showcase[data-service="intelligence"] {
  --svc: var(--svc-intelligence); --svc-ink: var(--svc-intelligence-ink);
  --svc-soft: var(--svc-intelligence-soft); --svc-glow: var(--svc-intelligence-glow);
}
.showcase[data-service="content"] {
  --svc: var(--svc-content); --svc-ink: var(--svc-content-ink);
  --svc-soft: var(--svc-content-soft); --svc-glow: var(--svc-content-glow);
}
.showcase[data-service="growth"] {
  --svc: var(--svc-growth); --svc-ink: var(--svc-growth-ink);
  --svc-soft: var(--svc-growth-soft); --svc-glow: var(--svc-growth-glow);
}
.showcase[data-service="foundation"] {
  --svc: var(--svc-foundation); --svc-ink: var(--svc-foundation-ink);
  --svc-soft: var(--svc-foundation-soft); --svc-glow: var(--svc-foundation-glow);
}

/* Ambient glow in the active service's colour, cross-fading on switch. */
.showcase {
  box-shadow: var(--glass-shadow),
              0 0 0 1px var(--svc-soft),
              0 24px 72px -28px var(--svc-glow);
  transition: box-shadow var(--transition-slow);
}

.showcase-window {
  position: relative;
  display: flex;
  flex-direction: column;
  /* Reserves the stage Phase B mounts a 3D object into, so nothing shifts when
     it arrives. */
  min-height: 420px;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-window);
  background: var(--glass-bg-solid);
  /* Clips the toolbar's flat top and the stage's flat bottom to the window's
     own rounded corners, and clips the JS-mounted canvas (absolute, inset:0)
     to the same shape. */
  overflow: hidden;
}

/* App-window chrome above the panels: three muted "traffic light" dots plus
   the active service name on the left, an empty slot on the right for the
   render-mode control a later task mounts. Positioned + z-index'd above the
   canvas (which the JS in index.js appends as the last child of
   .showcase-window, absolutely positioned, inset:0, z-index:0) with its own
   opaque background, so the 3D layer always renders beneath this bar rather
   than under it. */
.window-toolbar {
  position: relative;
  z-index: 2;
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: var(--space-4);
  height: 48px;
  padding: 0 var(--space-5);
  border-bottom: 1px solid var(--glass-border);
  background: var(--glass-bg-solid);
}

.window-dots {
  display: flex;
  flex: 0 0 auto;
  gap: var(--space-2);
}

.window-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--line-strong);
}

/* Allowed to shrink and truncate: with the mode control also occupying the
   toolbar (up to ~3 buttons wide) the two together can overflow it on
   narrow cards, which would cause a horizontal scrollbar — the one thing
   this whole system is not allowed to do. */
.window-title {
  overflow: hidden;
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* JS mounts the Studio/Wireframe/X-Ray segmented control into this slot
   (index.js, full/lite tiers only) — empty, and stays empty, without JS. */
.window-controls {
  flex: 0 0 auto;
  margin-left: auto;
}

/* Render-mode segmented control. Never present in the no-JS DOM — built and
   injected by index.js. Same pill-track-with-white-chip language as the rest
   of the page's controls, just sunken instead of transparent. */
.mode-control {
  display: flex;
  flex: 0 0 auto;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
}

.mode-btn {
  border: 0;
  border-radius: var(--radius-pill);
  padding: var(--space-2) var(--space-4);
  background: transparent;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--transition), color var(--transition), box-shadow var(--transition);
}

.mode-btn:hover {
  color: var(--text);
}

.mode-btn.is-active {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}

@media (prefers-reduced-motion: reduce) {
  .mode-btn {
    transition: none;
  }
}

/* The panel area proper: a faint dot grid on a barely-off-white surface reads
   as an app canvas rather than blank space, behind both the panel copy and
   wherever the 3D object doesn't cover it. */
.window-stage {
  position: relative;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  padding: var(--space-6);
  background-color: var(--surface-stage);
  background-image: radial-gradient(var(--line) 1px, transparent 1px);
  background-size: 24px 24px;
}

.panel {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--space-4);
}

/* Without JS every panel renders, stacked — a hairline keeps them legible as
   five separate things. Once tabs.js marks the document, the rule retires. */
html:not(.js-tabs) .panel + .panel {
  margin-top: var(--space-6);
  padding-top: var(--space-6);
  border-top: 1px solid var(--line);
}

.panel h2 {
  font-size: clamp(24px, 3vw, 34px);
}

.panel p {
  max-width: 52ch;
  color: var(--text-dim);
}

.panel-link {
  align-self: flex-start;
}

/* Empty in this phase: it simply absorbs the window's spare height. */
.panel-stage {
  flex: 1 1 auto;
}

/* ── Floating decorative chips ──────────────────────────────────────────── */

/* Reuses .chip's pastel-fill + text treatment (already the page's language for
   a small labeled pill) and layers on absolute positioning, a shadow so it
   reads as a little floating UI card, and a gentle drift. Purely decorative:
   aria-hidden, inert to pointer events, gone under 900px or reduced motion. */
.float-chip {
  position: absolute;
  z-index: 5;
  box-shadow: var(--shadow-sm);
  font-size: 13px;
  white-space: nowrap;
  pointer-events: none;
  animation: chip-float 6s ease-in-out infinite alternate;
}

.float-chip--a {
  top: -16px;
  left: 28px;
  animation-delay: 0s;
}

.float-chip--b {
  top: -16px;
  right: 28px;
  animation-delay: 2s;
}

.float-chip--c {
  top: 42%;
  right: -24px;
  animation-delay: 4s;
}

@keyframes chip-float {
  from { transform: translateY(0) rotate(-1deg); }
  to   { transform: translateY(-8px) rotate(1.5deg); }
}

@media (max-width: 900px) {
  .float-chip {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .float-chip {
    display: none;
  }
}

/* ── §2.5 Marquee ───────────────────────────────────────────────────────────
   Borrowed from the kinetic-typography reference: a constantly-moving strip.
   Kept in-system by staying full-bleed-but-quiet — surface-sunken bg, hairline
   borders, one hue per service pulled from the existing --svc-* tokens, no
   gradient fade at the edges (that part of the reference is right: a hard cut
   reads cleaner than a fade here). Track is duplicated once in the markup and
   the keyframe runs it exactly -50%, so the loop seam is invisible. */

.marquee {
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--surface-sunken);
}

.marquee-track {
  display: flex;
  width: max-content;
  gap: var(--space-8);
  padding: var(--space-4) 0;
  animation: marquee-scroll 32s linear infinite;
}

.marquee-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  white-space: nowrap;
  color: var(--text-dim);
  font-size: 15px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.marquee-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--dot, var(--svc-build));
  flex-shrink: 0;
}

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
  }
}

/* ── §3–§5 shared rhythm ────────────────────────────────────────────────── */

/* .section's default --space-10 block padding would put 256px between every
   pair of sections and only 128px before the CTA. Flattening the three middle
   sections to --space-9 gives one even 176px beat all the way down the page. */
.process,
.proof,
.about {
  padding-top: var(--space-9);
  padding-bottom: var(--space-9);
}

/* ── §3 Process ─────────────────────────────────────────────────────────── */

.process h2 {
  margin-bottom: var(--space-8);
  text-align: center;
}

.process-grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-4);
}

/* Connector line behind the four step numbers. Sits at the step number's
   vertical centre (card padding-top 40px + half its 40px line-height); the
   opaque card background in front of it means it only reads in the gaps
   between cards, like a line threading the numbers together. Drawn 0→1 by a
   one-shot ScrollTrigger tween in motion.js, not a continuous scrub, so
   scrolling back up never un-draws it. Only makes sense as a single row, so
   it's hidden once the grid wraps to 2/1 columns below. */
.process-line {
  position: absolute;
  z-index: 0;
  top: 60px;
  right: var(--space-5);
  left: var(--space-5);
  height: 2px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: left center;
}

.step {
  position: relative;
  z-index: 1;
  padding: var(--space-6) var(--space-5);
  border-radius: var(--radius-window);
}

.step-num {
  display: block;
  margin-bottom: var(--space-6);
  color: var(--text-dim);
  font-size: 40px;
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
}

.step h3 {
  margin-bottom: var(--space-3);
  font-size: 19px;
}

.step p {
  font-size: 15px;
}

/* ── §4 Proof ───────────────────────────────────────────────────────────── */

.proof h2 {
  margin-bottom: var(--space-8);
  text-align: center;
}

.proof-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-4);
}

/* Deliberately unboxed: §3 already spends four cards, and a second row of them
   would read as clutter. The numbers sit straight on the canvas. */
.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* space-between pins the chips to the bottom of the grid row, so the labels
     still line up when the two placeholder values wrap to different heights. */
  justify-content: space-between;
  padding: var(--space-5);
  border-radius: var(--radius-window);
  text-align: center;
}

.stat .chip {
  margin-top: var(--space-4);
}

.stat-value {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: clamp(48px, 9vw, 108px);
  max-width: 100%;
  color: var(--text);
  font-size: clamp(48px, 9vw, 108px);
  font-weight: 800;
  letter-spacing: -0.05em;
  line-height: 1;
}

/* Unfilled client data. Sized to wrap inside its cell and drawn as an obviously
   empty slot, so it cannot be mistaken for a shipped figure. */
.stat-value--input {
  padding: var(--space-3) var(--space-4);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

/* ── §5 About ───────────────────────────────────────────────────────────── */

.about {
  text-align: center;
}

.about-inner {
  max-width: 54ch;
  margin: 0 auto;
}

.about p {
  margin-bottom: var(--space-5);
  color: var(--text);
  font-size: clamp(19px, 2vw, 24px);
  letter-spacing: -0.015em;
  line-height: 1.45;
}

/* ── §6 CTA ─────────────────────────────────────────────────────────────── */

.cta {
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--space-9) var(--space-5) var(--space-10);
}

/* The page's only dark block. */
.cta-inner {
  padding: var(--space-10) var(--space-5);
  border-radius: var(--radius-card);
  background: var(--ink);
  box-shadow: var(--shadow-ink);
  text-align: center;
}

.cta h2 {
  margin-bottom: var(--space-6);
  color: var(--on-ink);
}

.cta .btn--ghost {
  border-color: transparent;
}

/* The shared focus ring is --text, which vanishes against --ink. */
.cta .btn:focus-visible {
  outline-color: var(--on-ink);
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

.footer {
  border-top: 1px solid var(--glass-border);
  background: var(--glass-bg-solid);
  color: var(--text-dim);
}

.footer .container {
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--space-9) var(--space-5) var(--space-6);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: var(--space-6);
}

.footer-logo img {
  width: auto;
  height: 30px;
}

.footer-tagline {
  margin-top: var(--space-4);
  font-size: 15px;
}

.footer h4 {
  margin-bottom: var(--space-4);
  color: var(--text);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.footer ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer li,
.footer a {
  font-size: 15px;
}

.footer a {
  color: var(--text-dim);
  text-decoration: none;
  transition: color var(--transition);
}

.footer a:hover {
  color: var(--text);
}

.social-icons {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

.social-icons a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 600;
  transition: border-color var(--transition), color var(--transition);
}

.social-icons a:hover {
  border-color: var(--line-strong);
}

.footer-bottom {
  margin-top: var(--space-8);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
  font-size: 14px;
}

/* ── Responsive ─────────────────────────────────────────────────────────── */

/* Measured natural widths of the five-tab row against the track:
     >=1200  971 / 1086  — icons, 14px, full padding
     1199    901 /  ~985 — padding trimmed
     1099    732 /  ~985 — icons dropped, 13px
      ~830   732 /  ~716 — row stops fitting; the track scrolls from here down.
   Without these two steps the row clips by 9px at 1024 and by 114px at 901. */
@media (max-width: 1199px) {
  .tab {
    padding-right: var(--space-3);
    padding-left: var(--space-3);
  }
}

@media (max-width: 1099px) {
  .tab-icon {
    display: none;
  }

  .tab {
    font-size: 13px;
  }
}

@media (max-width: 900px) {
  .process-grid,
  .proof-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  /* A single-row connector no longer makes sense once the grid wraps. */
  .process-line {
    display: none;
  }

  .footer-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-8) var(--space-6);
  }
}

@media (max-width: 767px) {
  .navbar .container {
    gap: var(--space-4);
    padding-right: var(--space-4);
    padding-left: var(--space-4);
  }

  .navbar .logo img {
    height: 32px;
  }

  /* Nav links scroll inside their own box instead of wrapping the bar onto two
     rows or overflowing the page. */
  .nav-links {
    gap: var(--space-4);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }

  .nav-links::-webkit-scrollbar {
    display: none;
  }

  /* Home. At 375px the row is ~27px too wide and clips "Get in Touch"; the logo
     beside it already links home, so the duplicate is what goes. */
  .nav-links > li:first-child {
    display: none;
  }

  .nav-links a {
    font-size: 14px;
  }

  .nav-links .btn-primary {
    min-height: 36px;
    padding: var(--space-3) var(--space-4);
    font-size: 14px;
  }

  /* A hover-revealed menu has no touch equivalent; the parent link still reaches
     services.html, and all five pages are listed in the footer. */
  .nav-dropdown-menu {
    display: none;
  }

  .hero {
    padding-top: calc(var(--space-9) + var(--space-7));
    padding-bottom: var(--space-8);
  }

  .hero-shell {
    padding: var(--space-6) var(--space-4);
    border-radius: 24px;
  }

  .hero-actions {
    margin-bottom: var(--space-8);
  }

  .hero-actions .btn {
    flex: 1 1 auto;
  }

  /* Same flattening as desktop, one step tighter: 112px between sections. */
  .process,
  .proof,
  .about {
    padding-top: var(--space-8);
    padding-bottom: var(--space-8);
  }

  .cta {
    padding-top: var(--space-8);
    padding-bottom: var(--space-9);
  }

  .showcase {
    padding: var(--space-4);
  }

  .showcase-window {
    min-height: 320px;
  }

  /* The three chrome dots are purely decorative; dropping them on narrow
     cards reclaims room so the title (now ellipsis-truncating) and the
     3-button mode control don't force a horizontal scrollbar. */
  .window-toolbar {
    gap: var(--space-3);
    padding: 0 var(--space-4);
  }

  .window-dots {
    display: none;
  }

  /* At this width the title has already lost the dots' room and still can't
     coexist with the 3-button mode control without truncating to "App…" —
     unreadable and worse than just not being there. The mode control is the
     functional piece; the title is decorative chrome, so it loses first. */
  .window-title {
    display: none;
  }

  .mode-btn {
    padding: var(--space-2) var(--space-3);
    font-size: 11px;
  }

  .window-stage {
    padding: var(--space-5);
  }

  .process h2,
  .proof h2 {
    margin-bottom: var(--space-7);
  }

  .cta-inner {
    padding: var(--space-9) var(--space-5);
  }
}

@media (max-width: 600px) {
  .process-grid,
  .footer-grid {
    grid-template-columns: 1fr;
  }

  /* The stats stay 2-up — four stacked numbers would be a long, empty scroll —
     so the padding has to give instead, or the chip labels wrap to three lines. */
  .stat {
    padding: var(--space-4) var(--space-3);
  }

  .step-num {
    margin-bottom: var(--space-5);
  }
}

/* Blur budget. Behind .step/.stat there is only a smooth gradient, so dropping
   their backdrop-filter on narrow screens and on the touch/low-memory tier
   costs almost nothing visually and removes up to 8 blurred surfaces. */
@media (max-width: 899px) {
  .step,
  .stat {
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
}

@media (max-width: 767px) {
  .aurora-blob--3 { display: none; }

  .aurora-blob::before { filter: blur(var(--aurora-blur-sm)); }
}

html.tier-lite .aurora-blob--3 { display: none; }

html.tier-lite .step,
html.tier-lite .stat {
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
}

@media (prefers-reduced-motion: reduce) {
  .nav-links .btn-primary:hover {
    transform: none;
  }

  .nav-dropdown-menu,
  .panel-link svg,
  .text-link svg,
  .tab,
  .navbar,
  .navbar.is-scrolled,
  .navbar .container {
    transition: none;
  }

  .panel-link:hover svg,
  .text-link:hover svg {
    transform: none;
  }

  /* Aurora keeps its colour and its veil — the page keeps its whole identity,
     it just stops moving. Blur is a static surface property, not motion, so
     the glass itself is deliberately left alone. */
  .aurora-blob,
  .aurora-blob::before {
    animation: none;
    will-change: auto;
  }

  /* Hover lift and glow stay — a state change on hover is an affordance, not
     an animation — but they arrive instantly. */
  .glass-hover,
  .glass-hover::after {
    transition: none;
  }
}

/* --- Tab mode: only active once tabs.js has booted. Without .js-tabs every
   panel stays visible and stacked, which is the no-JS baseline. --- */

.js-tabs .panel[hidden] { display: none; }

.js-tabs .panel {
  animation: panel-in var(--transition) both;
}

@keyframes panel-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .js-tabs .panel { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   DARK GLASS SURFACES
   ══════════════════════════════════════════════════════════════════════════
   Every glass surface (hero shell, showcase, tabs, step cards, stat cards)
   renders near-black while the page, gutters and aurora stay light. Removing
   this one block restores the all-light page exactly.

   Implemented by rebinding surface + ink tokens on the three container roots
   — .hero-shell (which contains .showcase, its tabs, window and panels),
   .step and .stat — rather than by restyling each component. Descendants
   already read these tokens, so they inherit the dark context automatically.

   The --svc-*-ink rebinding is the important one. Those darkened forms exist
   *only* because the vivid hues score 2.1–3.5:1 on white (see the token
   block at the top of this file). On a near-black surface that reasoning
   inverts: the vivid values are the accessible ones and the darkened forms
   would be the failures, so inside these surfaces the -ink channel points
   back at the vivid hue. Measured on the composited card (~#1b1c1f):
   build 5.6:1, intelligence 4.9:1, content 5.5:1, growth 9.5:1,
   foundation 7.7:1 — all clearing AA. */

.hero-shell,
.step,
.stat {
  /* Alpha is high on purpose: at 0.78 the light aurora behind still washes
     through to a mid-grey. 0.92 composites to ~#1b1c1f over the brightest
     aurora, which reads as black while keeping the backdrop-filter glass. */
  --glass-bg: rgba(9, 10, 13, 0.92);
  --glass-bg-solid: rgba(9, 10, 13, 0.96);
  --glass-border: rgba(255, 255, 255, 0.14);
  --glass-rim: rgba(255, 255, 255, 0.30);
  --glass-rim-soft: rgba(255, 255, 255, 0.08);

  /* Nested light surfaces inside these cards. */
  --surface: #14161a;
  --surface-sunken: #0f1114;
  --surface-strong: rgba(255, 255, 255, 0.08);
  --surface-stage: rgba(9, 10, 13, 0.94);

  --line: rgba(255, 255, 255, 0.10);
  --line-strong: rgba(255, 255, 255, 0.18);

  --text: #fafafa;
  --text-dim: rgba(255, 255, 255, 0.66);

  /* The vivid hue is the accessible one here — see the note above. */
  --svc-build-ink: var(--svc-build);
  --svc-intelligence-ink: var(--svc-intelligence);
  --svc-content-ink: var(--svc-content);
  --svc-growth-ink: var(--svc-growth);
  --svc-foundation-ink: var(--svc-foundation);
  --svc-ink: var(--svc);

  /* The light page's shadows are tuned for dark-on-light and vanish here. */
  --glass-shadow: 0 1px 2px rgba(0, 0, 0, 0.35),
                  0 12px 32px rgba(0, 0, 0, 0.45),
                  0 32px 64px rgba(0, 0, 0, 0.35);
  --glass-shadow-lift: 0 2px 6px rgba(0, 0, 0, 0.4),
                       0 20px 48px rgba(0, 0, 0, 0.55);

  /* Required, not redundant. `body` sets `color: var(--text-dim)`, which
     resolves to the light-page ink *at body* and then inherits down as an
     already-computed value — rebinding --text-dim above cannot reach it.
     Re-declaring color here re-resolves it inside the dark context. Without
     this, body copy in the cards sits at 3.14:1 (measured). */
  color: var(--text-dim);
}

/* .btn--primary is --ink (near-black) on white — invisible on a black card.
   Inside these surfaces it inverts to the light-on-dark equivalent. */
.hero-shell .btn--primary {
  background: var(--text);
  color: #0a0a0b;
}

.hero-shell .btn--ghost {
  border-color: var(--glass-border);
  color: var(--text);
}

/* ══════════════════════════════════════════════════════════════════════════
   TOUCH TARGETS
   ══════════════════════════════════════════════════════════════════════════
   Measured on a real touch viewport: footer and nav links rendered 17–19px
   tall and the header CTA 36px, all under the 44px minimum. Keyed on
   (pointer: coarse) rather than a width breakpoint because this is about the
   input device, not the screen size — a small window on a mouse-driven
   machine does not need fatter targets, and a large tablet does. */

@media (pointer: coarse) {
  .nav-links > li > a,
  .nav-dropdown-menu a,
  .footer-grid a,
  .footer-bottom a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  /* Icon buttons need width as well as height. */
  .social-icons a {
    min-width: 44px;
    min-height: 44px;
  }

  .navbar .btn,
  .nav-links .btn-primary,
  .btn {
    min-height: 44px;
  }

  /* summary is the FAQ's whole hit area. */
  .faq-item summary {
    min-height: 44px;
  }
}
