/* ==========================================================================
   Pinnacle Technologies — base styles
   Tokens sourced from Figma file "Pinnacle-Technologies-Website"
   ========================================================================== */

:root {
  --bg: #04070b;
  --bg-panel: #080a0d;
  --text: #f4f1ea;
  --text-muted: #8b92a0;
  --accent: #e8633d;
  --accent-hover: #d6522e;
  --border-soft: rgba(139, 146, 160, 0.49);
  --glow: #001077;

  --font-display: "Space Grotesk", sans-serif;
  --font-body: "Inter", sans-serif;
  --font-eyebrow: "Kanit", sans-serif;

  --header-h: clamp(64px, 9vw, 110px);
  --container-pad: clamp(20px, 11.3vw, 217px); /* matches Figma's 217px hero margin at the 1920px reference frame */
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
}

/* While the splash intro is playing, the page is locked in place so the
   user can't scroll (or wheel-snap between sections) out from under it. */
html.is-scroll-locked,
html.is-scroll-locked body {
  overflow: hidden;
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  overflow-x: hidden;
}

/* Products/Work/detail pages (products.html, work.html, product-*.html)
   stack sections that all use #0d1117, but several are .scroll-reveal
   (opacity:0 until scrolled into view) — while hidden, their own
   background is invisible too, so the body's --bg (#04070b, a visibly
   different near-black) shows through as a seam until the reveal fires.
   Scoped to these pages only — the homepage deliberately lets --bg
   show through .hero/.stats to keep one continuous glow background,
   so it must keep the default body background untouched. */
body.product-page {
  background: #0d1117;
}

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--accent);
  color: #fff;
  padding: 10px 16px;
  z-index: 999;
}
.skip-link:focus { left: 10px; top: 10px; }

/* ==========================================================================
   Preloader / splash sequence
   ========================================================================== */

#preloader {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.7s ease, visibility 0.7s ease;
}

#preloader.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* The solid backdrop lives here, as two seamless halves, instead of on
   #preloader itself — so they can physically separate in Phase 4 and reveal
   the hero page through the widening gap, rather than the background
   staying a static block while only the logo appears to move. */
.preloader-panel {
  position: absolute;
  left: 0;
  right: 0;
  height: 50%;
  background: var(--bg-panel);
  z-index: 0;
}

.preloader-panel--top { top: 0; }
.preloader-panel--bottom { bottom: 0; }

.preloader-panel--top.panel-split {
  transition: transform 1.15s cubic-bezier(.65,0,.35,1);
}

.preloader-panel--bottom.panel-split {
  transition: transform 1.15s cubic-bezier(.55,0,.85,.35);
}

.preloader-stage {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* The word row has zero intrinsic width — its children are positioned
   absolutely, anchored to this element's center. That keeps the icon
   pinned to the true viewport center instead of drifting with a
   flex-centered row whose two wings are unequal widths. */
.preloader-word {
  position: relative;
}

.letter img,
.letter-icon img {
  display: block;
  width: 100%;
  height: 100%;
}

.letter {
  position: absolute;
  top: 50%;
  left: 50%;
  opacity: 0;
  transition: opacity 0.6s cubic-bezier(.65,0,.35,1), transform 0.6s cubic-bezier(.65,0,.35,1);
}

.letter-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  opacity: 1;
  transition: width 0.55s cubic-bezier(.65,0,.35,1), height 0.55s cubic-bezier(.65,0,.35,1);
}

/* Phase 1 — scales up past its resting size, then back down, settling like a beat */
@keyframes iconBeat {
  0%   { transform: translate(-50%, -50%) scale(0.55); }
  38%  { transform: translate(-50%, -50%) scale(1.22); }
  64%  { transform: translate(-50%, -50%) scale(0.9); }
  100% { transform: translate(-50%, -50%) scale(1); }
}

.letter-icon.is-beating {
  animation: iconBeat 1.8s cubic-bezier(.22,1,.36,1) both;
}

/* Phase 3 — TECHNOLOGIES sub-wordmark slides up + fades in, tracking
   expanded via scaleX so its width locks to PINNACLE's outer bounds. */
.preloader-sub {
  position: absolute;
  left: 50%;
  max-width: none; /* override the global img{max-width:100%} — preloader-stage
                       is intentionally near-zero width so the icon anchors dead
                       center, which would otherwise crush this image to 0px */
  opacity: 0;
  transition: opacity 0.55s ease, transform 0.55s cubic-bezier(.65,0,.35,1);
}

/* Phase 4 — vertical split ("shutter" opening): PINNACLE rises, scales down
   and docks into the header logo; TECHNOLOGIES drops away, fading out evenly
   across the same journey rather than cutting late — the two halves pulling
   apart in sync to clear the canvas from the center out. */
.preloader-word.word-dock {
  transition: transform 1.15s cubic-bezier(.65,0,.35,1);
}

.preloader-sub.sub-exit {
  transition: opacity 1.1s linear, transform 1.15s cubic-bezier(.55,0,.85,.35);
}

@media (prefers-reduced-motion: reduce) {
  #preloader { display: none; }
}

/* ==========================================================================
   Header
   ========================================================================== */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);
  background: rgba(0, 5, 13, 0.35);
  border-bottom: 1px solid var(--border-soft);
  opacity: 0;
  transform: translateY(-12px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.site-header.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.header-inner {
  width: 100%;
  /* No max-width/auto-margin centering here — the header is full-bleed in
     the Figma design (frame spans the full 1920px width), and using the
     same container-pad directly as .hero keeps the logo's left edge flush
     with the headline's instead of adding an extra centering offset. */
  padding: 0 var(--container-pad);
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 40px);
}

.brand {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.brand.is-visible { opacity: 1; }

.brand-logo {
  height: clamp(30px, 3.4vw, 44px);
  width: auto;
}

.header-divider {
  width: 1px;
  align-self: stretch;
  margin: 20px 0;
  background: var(--border-soft);
  flex-shrink: 0;
}

.main-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(28px, 3.6vw, 56px);
  flex: 1;
}

.main-nav > * {
  opacity: 0;
  transform: translate(16px, -12px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.site-header.is-visible .main-nav > * { opacity: 1; transform: translate(0, 0); }
.site-header.is-visible .main-nav > *:nth-child(1) { transition-delay: 0.05s; }
.site-header.is-visible .main-nav > *:nth-child(2) { transition-delay: 0.1s; }
.site-header.is-visible .main-nav > *:nth-child(3) { transition-delay: 0.15s; }
.site-header.is-visible .main-nav > *:nth-child(4) { transition-delay: 0.2s; }
.site-header.is-visible .main-nav > *:nth-child(5) { transition-delay: 0.25s; }

/* Duplicate of .header-cta, shown only inside the mobile dropdown
   (see the ≤860px override below) — .header-cta itself is hidden at
   that width, so without this the open mobile menu had no "Get in
   Touch" CTA at all. */
.nav-mobile-cta {
  display: none;
}

.nav-link {
  font-family: var(--font-display);
  font-size: clamp(14px, 1.05vw, 18px);
  color: var(--text);
  white-space: nowrap;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.nav-link.is-active { color: var(--accent); }
.nav-link:hover { color: var(--accent); }

.nav-dropdown { position: relative; }

.nav-dropdown-menu {
  position: absolute;
  top: calc(100% + 14px);
  left: 0;
  min-width: 160px;
  background: var(--bg-panel);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
}

.nav-dropdown-menu.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.nav-dropdown-menu a {
  padding: 8px 10px;
  border-radius: 6px;
  font-family: var(--font-body);
  font-size: 15px;
}
.nav-dropdown-menu a:hover { background: rgba(255,255,255,0.06); }

.btn-primary {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(13px, 1vw, 18px);
  background: var(--accent);
  color: #fff;
  padding: 10px 20px;
  border-radius: 8px;
  white-space: nowrap;
  flex-shrink: 0;
  transition: background 0.2s ease;
}
.btn-primary:hover { background: var(--accent-hover); }

.header-cta {
  margin-left: auto;
  opacity: 0;
  transform: translate(16px, -12px);
  transition: background 0.2s ease, opacity 0.5s ease 0.3s, transform 0.5s ease 0.3s;
}

.site-header.is-visible .header-cta { opacity: 1; transform: translate(0, 0); }

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 32px;
  height: 32px;
  background: none;
  border: none;
  cursor: pointer;
  margin-left: auto;
}
.nav-toggle span {
  display: block;
  height: 2px;
  background: var(--text);
  border-radius: 2px;
  transition: transform 0.25s ease, opacity 0.25s ease;
}

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

.hero {
  position: relative;
  z-index: 0; /* pins its own stacking context so .hero-glow's negative
                 z-index stays scoped here instead of escaping upward */
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: calc(var(--header-h) + 40px) var(--container-pad) 80px;
  overflow: clip;
}

.hero-glow {
  /* Full-viewport fixed backplate. Shape matches the actual Figma source
     (node 20:155): a symmetric elliptical RING (#001077, 94px Gaussian
     blur) — outer rx/ry ≈ 1105.5/667.5, inner rx/ry ≈ 942.3/569.0, centered
     at ~(50.2%, 61.6%) of the 1920x1080 frame. Converted to viewport-
     relative radii: outer ≈ 58%/62%, with the inner hole boundary sitting
     at ~85% of that radius — so the center (behind the headline) and the
     area beyond the ring both stay dark, with only the band in between lit.
     Not an asymmetric corner-boosted vignette — the design is symmetric. */
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  background: radial-gradient(ellipse 58% 70% at 50% 62%,
    transparent 0%,
    transparent 62%,
    rgba(0, 16, 119, 0.55) 80%,
    rgba(0, 16, 119, 0.75) 93%,
    transparent 100%);
  filter: blur(60px);
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transition: opacity 1s ease-in-out;
}

/* Fades in only during Phase 4 (the shutter split) — triggered alongside
   header.is-visible in dockIntoHeader(), in tandem with the header and
   headline entrance, not on page load. */
.hero.is-glow-visible .hero-glow { opacity: 1; }

.hero-inner { position: relative; z-index: 2; max-width: 1180px; }

/* Phase 5 — headline reveal */
.hero-title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(2.1rem, 5.4vw, 5rem);
  line-height: 1.12;
  margin: 0 0 28px;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.hero.is-title-revealed .hero-title { opacity: 1; transform: translateY(0); }

/* Phase 6 — typewriter subtext */
.hero-subtitle {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.6vw, 1.75rem);
  line-height: 1.5;
  color: var(--text);
  max-width: 62ch;
  margin: 0 0 40px;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.hero.is-subtitle-revealed .hero-subtitle { opacity: 1; transform: translateY(0); }

.hero-subtitle .brace {
  color: var(--accent);
  font-size: 1.3em;
  font-weight: 700;
}

.typewriter-cursor {
  display: inline-block;
  width: 2px;
  height: 0.95em;
  margin-left: 2px;
  background: var(--accent);
  vertical-align: text-bottom;
  opacity: 0;
  animation: cursorBlink 0.9s step-end infinite;
}

.hero.is-typing .typewriter-cursor { opacity: 1; }

@keyframes cursorBlink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

/* Phase 7 — CTA fade-up */
.hero-actions {
  display: flex;
  align-items: center;
  gap: clamp(20px, 3vw, 58px);
  flex-wrap: wrap;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.hero.is-actions-revealed .hero-actions { opacity: 1; transform: translateY(0); }

.btn-secondary {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(14px, 1.2vw, 24px);
  /* Normal state (node 20:214): frosted-glass card — translucent fill,
     backdrop blur, and a faint border to sell the glass edge. */
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--text);
  padding: 14px 22px;
  border-radius: 8px;
  transition: background 0.25s ease, border-color 0.25s ease;
}

/* Hover state (node 435:9930): same glass base, tinted with a bottom-lit
   blue glow gradient and a cooler border — geometry (206x63, text at
   20,16) is identical to the normal state, so padding stays fixed here
   rather than the slightly different value Figma's export reported, to
   avoid a size jump on hover. */
.btn-secondary:hover {
  background:
    linear-gradient(to top,
      rgba(4, 18, 99, 0.34) 7.291%,
      rgba(4, 26, 152, 0.43) 44.627%,
      rgba(0, 0, 0, 0) 138.89%),
    rgba(255, 255, 255, 0.1);
  border-color: rgba(71, 74, 98, 0.73);
}

.link-underline {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(14px, 1.2vw, 24px);
  position: relative;
}
.link-underline::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -4px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s ease;
}
.link-underline:hover::after { transform: scaleX(1); }

/* ==========================================================================
   Stats
   ========================================================================== */

.stats {
  position: relative;
  /* No solid fill here — the design keeps the same dark/glowing atmosphere
     as the hero, so .hero-glow (fixed, behind the content) must stay
     visible through this section instead of being blocked by an opaque
     panel color. */
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: calc(var(--header-h) + 40px) var(--container-pad) 80px;
  overflow: clip;
}

.stats-content {
  position: relative;
  z-index: 1;
  width: 100%;
}

/* Eyebrow badge (Figma node 444:11280) — a bordered pill with a small
   dot and the section's label, replacing the earlier bracket-line
   design. Exact figures from the Figma frame (350x72 reference):
   17px vertical / ~15px horizontal padding, 12px gap, 2px border.
   The border itself isn't a flat color — Figma renders it as a
   gradient stroke (blue, with a red/magenta highlight radiating from
   the top edge) that the design-context tool's codegen flattened to
   a single blue when this was first built. Reproduced here via the
   standard two-background gradient-border technique (a solid fill
   clipped to padding-box, a gradient clipped to border-box) since
   plain `border-color` can't take a gradient and `border-image`
   doesn't respect border-radius. */
.section-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 17px 15px;
  background:
    rgba(40, 41, 48, 0.46) padding-box,
    radial-gradient(ellipse at top, #ff2d55 0%, #001fff 70%) border-box;
  border: 2px solid transparent;
  border-radius: 12px;
  /* Sits closer to the true left edge than the rest of the section's
     content (which uses container-pad), and pulled up slightly with a
     bigger gap below before the stats grid, matching the design. */
  margin-left: calc(var(--container-pad) * -0.25);
  margin-top: -28px;
  margin-bottom: 100px;
  opacity: 0;
  transform: translateY(80px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.stats.is-revealed .section-eyebrow { opacity: 1; transform: translateY(0); }

/* Services'/Products' eyebrow-to-content gap only — shrunk from the
   shared 100px default, which read as an oversized empty band above
   the cards specifically on these two panels. */
.panel-services .section-eyebrow,
.panel-products .section-eyebrow {
  margin-bottom: 48px;
}

/* The static per-section eyebrow copies (Services/Products/Process/Why/
   Clients/FAQ) don't have a .stats.is-revealed-equivalent to flip them
   visible — they were still inheriting .section-eyebrow's default
   opacity:0 with nothing to ever override it, so they were flipping
   into their own .panel-section along with everything else but staying
   invisible forever. They ride along with .panel-section's own
   crossfade-in instead, so they just need to start visible. */
.section-eyebrow--static {
  opacity: 1;
  transform: translateY(0);
}

.section-eyebrow-dot {
  flex-shrink: 0;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #ededed;
}

.section-eyebrow-text {
  /* Matches node 444:11281 — Space Grotesk Medium, 30px, #ededed. */
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(20px, 2.2vw, 30px);
  color: #ededed;
  white-space: nowrap;
}

@media (max-width: 900px) {
  .section-eyebrow {
    gap: 10px;
    padding: 13px 12px;
    margin-bottom: 64px;
  }

  /* Without this, the desktop Services/Products override above
     (higher specificity: two classes vs. one) would keep winning at
     this width too, since it isn't itself scoped to a media query. */
  .panel-services .section-eyebrow,
  .panel-products .section-eyebrow {
    margin-bottom: 32px;
  }

  .section-eyebrow-dot {
    width: 10px;
    height: 10px;
  }

  .section-eyebrow-text {
    font-size: clamp(16px, 2.6vw, 22px);
  }
}

@media (max-width: 700px) {
  .section-eyebrow {
    gap: 8px;
    padding: 10px 10px;
    border-width: 1.5px;
    margin-bottom: 40px;
  }

  .section-eyebrow-dot {
    width: 8px;
    height: 8px;
  }

  .section-eyebrow-text {
    font-size: clamp(13px, 3.4vw, 16px);
  }
}

.stats-inner {
  max-width: 1180px;
  /* Indented well past the eyebrow's left edge — a deliberate asymmetry
     in the design, not a centered/flush-left block. */
  margin-left: clamp(0px, 21vw, 405px);
  display: flex;
  flex-direction: column;
  gap: clamp(40px, 6vw, 64px);
}

.stats-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 64px);
}

/* min-width:0 is needed alongside the grid's own minmax(0, 1fr)
   above — without it, this item's default min-width:auto still
   refuses to shrink below .stat-figure's content width (the big
   number + description sitting side by side with no wrap), pushing
   the whole row past the viewport at tablet/small-laptop widths
   where .stats-inner's margin-left already eats a lot of the
   available space. */
.stat {
  min-width: 0;
  opacity: 0;
  transform: translateY(80px);
  transition: opacity 0.7s ease-out, transform 0.7s ease-out;
}

.stats.is-revealed .stat { opacity: 1; transform: translateY(0); }
.stats.is-revealed .stats-row .stat:nth-child(2) { transition-delay: 0.12s; }
.stats.is-revealed .stat--wide { transition-delay: 0.24s; }

/* Number + description sit side by side beneath an underlined heading —
   matches the design (67:78), not a stacked number/label/description. */
.stat h3 {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.1rem, 1.6vw, 1.75rem);
  margin: 0 0 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border-soft);
}

.stat-figure {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(16px, 2.4vw, 32px);
}

.stat-number {
  font-family: "Inter", sans-serif;
  font-weight: 700;
  font-size: clamp(3rem, 7vw, 6.5rem);
  line-height: 1;
}

.stat--wide .stat-number { font-size: clamp(4rem, 10vw, 9rem); }

.stat-plus {
  font-family: "Inter", sans-serif;
  font-weight: 700;
  font-size: clamp(1.5rem, 3.5vw, 3.25rem);
  align-self: flex-start;
  margin-left: -8px;
}

/* Panel crossfade (Trusted By Clients <-> Our Services, same scroll position) */
.panel-stack {
  display: grid;
  width: 100%;
}

.panel-stack .panel {
  grid-area: 1 / 1;
  width: 100%;
  transition: opacity 0.7s ease-out, transform 0.7s ease-out;
}

.panel-stack .panel:not(.is-active) {
  opacity: 0;
  transform: translateY(80px);
  pointer-events: none;
}

.panel-stack .panel.is-active {
  opacity: 1;
  transform: translateY(0);
}

/* Trusted By Clients keeps the deliberate off-center indent from the
   design; Our Services is a symmetric bento grid, so it's centered
   instead of inheriting that same indent. */
.panel-trusted {
  max-width: 1180px;
  margin-left: clamp(0px, 21vw, 405px);
}

.panel-trusted .stats-inner { margin-left: 0; }

/* Services/Products/Process/Why/Clients/FAQ each live in their own real
   <section> (siblings of .stats) rather than sharing one scroll
   position — .panel-section is the base sizing + reveal-on-.is-active
   treatment every one of them shares (a copy of .panel-stack .panel's
   crossfade above, so "replay every time you revisit" keeps working
   the same way it already did for the grid-stacked panels), and
   .panel-section-inner is the max-width/centering layer, kept as a
   separate element from .panel-section's own padding so the padding
   doesn't eat into the 1180px cap (mirrors today's .stats ->
   .stats-content -> .panel-services nesting, just per-section). */
.panel-section {
  position: relative;
  z-index: 1;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: calc(var(--header-h) + 60px) var(--container-pad) 80px;
  overflow: clip;
  transition: opacity 0.7s ease-out, transform 0.7s ease-out;
}

.panel-section:not(.is-active) {
  opacity: 0;
  transform: translateY(80px);
  pointer-events: none;
}

.panel-section.is-active {
  opacity: 1;
  transform: translateY(0);
}

/* Full-width, uncapped wrapper around each section's eyebrow +
   .panel-section-inner — mirrors .stats-content's role for Trusted's
   own eyebrow. Without this, the eyebrow would sit *inside* the
   1180px-capped, centered .panel-section-inner, so its own
   margin-left (below) would be relative to that box's centered edge
   instead of the section's true padding edge — drifting further right
   than Trusted's eyebrow on any viewport wider than ~1180px + padding.
   Keeping it out here means every eyebrow's position only ever depends
   on --container-pad, so they all land in the exact same spot. */
.panel-section-content {
  width: 100%;
}

.panel-section-inner {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
}

/* Full-bleed, no max-width — lets the coverflow's side cards peek
   toward/off the section's own edges, clipped by .panel-section's own
   overflow:clip (the same role .stats's overflow:clip used to play
   when this was grid-stacked inside it). */
.panel-section-inner--clients {
  max-width: none;
}

/* Products panel (Figma node 111:2214, PRODUCTS eyebrow state) — a
   centered product card with a "View Details" / "Book a Demo" pair,
   and an "All Products" pill with pagination dots underneath. */
.product-showcase {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
  padding: 40px 0;
}

/* Auto-rotating carousel — all 5 product cards stacked in the same grid
   cell (same crossfade technique as .panel-stack), one .is-active at a
   time. JS (script.js) advances the active card on a timer. */
.product-card-stack {
  display: grid;
  width: 100%;
  justify-items: center;
}

/* Wraps .product-card-stack so the prev/next buttons can sit in the
   side gutters either side of the (narrower, centered) card without
   joining the crossfading stack themselves. Unlike products.html's
   edge-to-edge row, .panel-section-inner's 1180px cap leaves plenty of
   room beside the 575px card, so the arrows float clear of it instead
   of overlapping. */
.product-carousel-wrap {
  position: relative;
  width: 100%;
}

.product-carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease;
}

.product-carousel-arrow svg {
  width: 20px;
  height: 20px;
}

.product-carousel-arrow:hover {
  background: var(--accent);
}

.product-carousel-arrow--prev { left: 0; }
.product-carousel-arrow--next { right: 0; }

@media (max-width: 900px) {
  /* No side gutter left once the card grows to fill the narrower
     panel width — the dots below already cover pagination here. */
  .product-carousel-arrow {
    display: none;
  }
}

.product-card-stack .product-card {
  grid-area: 1 / 1;
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.product-card-stack .product-card:not(.is-active) {
  opacity: 0;
  transform: translateY(16px);
  pointer-events: none;
}

.product-card-stack .product-card.is-active {
  opacity: 1;
  transform: translateY(0);
}

.product-carousel-dots {
  display: flex;
  align-items: center;
  gap: 10px;
}

.product-carousel-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
  cursor: pointer;
  transition: background 0.25s ease, transform 0.25s ease;
}

.product-carousel-dot.is-active {
  background: var(--accent);
  transform: scale(1.3);
}

/* Same dot styling as .product-carousel-dots, reused for the Services
   phone carousel — hidden by default since Services is only a
   carousel at the ≤640px breakpoint (see .services-grid there), a
   static grid everywhere wider. */
.services-carousel-dots {
  display: none;
  align-items: center;
  gap: 10px;
}

.services-carousel-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
  cursor: pointer;
  transition: background 0.25s ease, transform 0.25s ease;
}

.services-carousel-dot.is-active {
  background: var(--accent);
  transform: scale(1.3);
}

/* Card body (Figma "Swaraj Card", 575x421 at 38px inner padding), plus
   the faint glowing rim lines top and bottom (Ellipse 67/68/69/70 —
   a bright thin line layered over a soft blurred halo). */
.product-card {
  position: relative;
  width: 100%;
  max-width: 575px;
  padding: 38px;
  background: linear-gradient(180deg, #0c1120 0%, #060810 100%);
  border-radius: 28px;
  overflow: hidden;
  box-shadow: 0 40px 100px rgba(0, 16, 119, 0.3);
}

.product-card::before,
.product-card::after {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  height: 6px;
  background: linear-gradient(90deg, transparent, rgba(120, 150, 255, 0.55), transparent);
  filter: blur(3px);
  pointer-events: none;
}

.product-card::before { top: -2px; }
.product-card::after { bottom: -2px; }

.product-card-name {
  margin: 0 0 40px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(16px, 3.4vw, 28px);
  color: var(--text);
}

.product-card-label {
  display: block;
  font-family: "Inter", sans-serif;
  font-size: 1rem;
  color: var(--text-muted);
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border-soft);
}

.product-card-value {
  margin: 16px 0 36px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(16px, 2vw, 24px);
  color: var(--text);
}

.product-card-tags {
  margin: 0 0 36px;
  display: flex;
  align-items: center;
  gap: 20px;
  color: var(--text-muted);
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 1.5vw, 1.4rem);
}

.product-card-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-muted);
}

.product-card-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.product-card-actions .btn-primary {
  padding: 14px 24px;
  border-radius: 12px;
}

/* Phone — the homepage's Products panel card carousel (not
   .products-scroll's card row on products.html, which is unaffected):
   smaller padding/margins and lower font-size floors shrink the
   card's overall height and text scale, which desktop's clamp()s
   alone don't reduce enough on a narrow phone. */
@media (max-width: 640px) {
  .product-card {
    padding: 24px;
  }

  .product-card-name {
    margin-bottom: 20px;
    font-size: clamp(1.5rem, 7vw, 2rem);
  }

  .product-card-label {
    font-size: 0.85rem;
    padding-bottom: 10px;
  }

  .product-card-value {
    margin: 10px 0 20px;
    font-size: clamp(16px, 5vw, 24px);
  }

  .product-card-tags {
    margin-bottom: 20px;
    gap: 12px;
    font-size: clamp(0.85rem, 4vw, 1rem);
  }

  .product-card-actions {
    gap: 12px;
  }

  .product-card-actions .btn-primary,
  .product-card-actions .btn-product-outline {
    padding: 11px 18px;
    font-size: 14px;
  }
}

/* Sits opposite the button in the same row (Work page's Raitasiri
   card — "Coming Soon!" instead of a second CTA). */
.product-card-note {
  margin: 0 0 0 auto;
  font-family: var(--font-display);
  font-size: clamp(14px, 1.5vw, 1.4rem);
  color: var(--text-muted);
}

/* "Book a Demo" — same frosted-glass treatment as .btn-secondary, sized
   down to match this card's button row instead of the hero's larger CTA. */
.btn-product-outline {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(14px, 1vw, 18px);
  padding: 14px 28px;
  border-radius: 12px;
  color: var(--text);
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.14);
  transition: background 0.2s ease, border-color 0.2s ease;
}

.btn-product-outline:hover {
  background:
    linear-gradient(to top,
      rgba(4, 18, 99, 0.34) 7.291%,
      rgba(4, 26, 152, 0.43) 44.627%,
      rgba(0, 0, 0, 0) 138.89%),
    rgba(255, 255, 255, 0.1);
  border-color: rgba(71, 74, 98, 0.73);
}

/* "All Products" CTA (Figma node 488:7012, Normal/Hover states) — a
   fixed-size dark pill with a white glow drop-shadow. The two small dots
   on the right morph into a single ring-with-dot "target" indicator on
   hover, rather than the text changing (both states render the same
   "All Products" label). */
.product-nav-pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 295px;
  max-width: 100%;
  height: 58px;
  padding: 0 16px 0 20px;
  background: #04070b;
  border: none;
  border-radius: 12px;
  box-shadow: 0 0 4px rgba(255, 255, 255, 0.45);
  color: #bdbdbd;
  font-family: "Inter", sans-serif;
  font-weight: 500;
  font-size: clamp(16px, 1.6vw, 20px);
  cursor: pointer;
  transition: box-shadow 0.25s ease;
}

.product-nav-pill:hover {
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.65);
}

.product-nav-indicator {
  position: relative;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
}

.product-nav-dot {
  position: absolute;
  top: 7px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid transparent;
  transition: left 0.25s ease, top 0.25s ease, width 0.25s ease, height 0.25s ease,
    background 0.25s ease, border-color 0.25s ease;
}

.product-nav-dot--a { left: 0; }
.product-nav-dot--b { left: 14px; background: rgba(255, 255, 255, 0.9); }

/* Hover: the two dots collapse into a concentric ring (dot A) + center
   dot (dot B), matching Ellipse77/Ellipse76 in the Hover variant. */
.product-nav-pill:hover .product-nav-dot--a {
  left: 0;
  top: 0;
  width: 26px;
  height: 26px;
  background: transparent;
  border-color: rgba(255, 255, 255, 0.5);
}

.product-nav-pill:hover .product-nav-dot--b {
  left: 7px;
  top: 7px;
  background: #fff;
}

/* Icon-only swap for the topbar's "Get in Touch" pill on phones (see
   the ≤640px override below) — hidden here so it never shows on the
   wider "All Products"/FAQ pills, which reuse .product-nav-pill but
   don't get this treatment. */
.product-nav-pill-icon {
  display: none;
}

/* Our Process panel (Figma nodes 127:3850 Discovery / 134:1136
   Strategy & Design / 134:1893 Development / 134:2650 Testing & Launch
   / 148:2923 Support & Growth) — a static left column (heading) beside
   a right column that's its own internally scrollable box. As of the
   card-stack redesign (matching about.html — see .about-process-card*
   in this file), #processRight reuses the SAME card markup/CSS as the
   About page; the only homepage-specific pieces are here: the scroll
   box itself (#processRight needs max-height + overflow-y:auto since
   this panel is wheel-snap-locked to one viewport, unlike the About
   page's normal page scroll) and the sticky offset override just
   below (position:sticky here is relative to #processRight's own
   scrollport, not the page, so it doesn't need the About page's
   topbar/divider-height math). See js/script.js for the interaction —
   it forwards captured wheel ticks into #processRight.scrollTop, then
   a scroll listener on the box itself (not wheel ticks — real
   scrollable content exists from the start now, unlike the old
   tab-accordion) decides which card is .is-active/.is-passed, exactly
   mirroring js/products.js's version of the same logic. */
.process-layout {
  display: flex;
  align-items: flex-start;
  gap: 100px;
  width: 100%;
}

.process-intro {
  flex: 0 0 auto;
  width: clamp(220px, 26vw, 340px);
}

.process-intro-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2rem, 3.2vw, 2.75rem);
  color: var(--text);
}

#processRight {
  max-height: min(600px, calc(100svh - var(--header-h) - 220px));
  overflow-y: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

#processRight::-webkit-scrollbar {
  display: none;
}

/* position:sticky here is relative to #processRight's own scrollport,
   not the page, so it doesn't need the About page's topbar/divider-
   height math — just a flat offset. */
#processRight .about-process-card {
  top: 8px;
}

/* .about-process-card:last-child's shared clamp(90px, 9vw, 130px)
   trailing runway (below) is tuned for the About page, where these
   cards scroll against the whole page. Measured directly in-browser,
   a trailing margin on the very last sticky child (no following
   sibling box, only empty space) doesn't actually hold it at top:8 the
   way cards 1-4 hold each other — it turns out to keep sliding right
   through in perfect lockstep with scroll, with no dwell at all.
   Cards 1-4 only look "stuck" because there's enough real content
   (the next card) below them to hold the pin for a while.

   So the fix here isn't really "give it a stick window" (nothing
   does) — it's landing #processRight's own scrollable end exactly
   where the last card's top would be ~8px, so running out of room to
   scroll IS what holds it in place, the same way it visually looks
   for the others. That end point = this box's own max-height minus
   the offset minus the card's own rendered height (~360px, roughly
   constant across the 5 cards) — tied to the same responsive formula
   #processRight's max-height uses above, not a fixed px, so it still
   lands correctly at whatever height a shorter viewport caps the box
   to instead of the 600px ceiling. */
#processRight .about-process-card:last-child {
  margin-bottom: calc(min(600px, 100svh - var(--header-h) - 220px) - 368px);
}

@media (max-width: 900px) {
  .process-layout { flex-direction: column; }
  .process-intro { position: static; width: 100%; }
}

/* Why Choose Us panel (Figma node 138:13325) — 5 numbered items in a
   diagonal staircase, each indented further right and down than the
   last, connected by an elbow line (a horizontal underline under each
   item, then a short vertical tick dropping to the next). */
.why-list {
  margin-top: -60px;
  padding: 0 0 40px;
}

/* --why-gap (vertical space between items) and --why-tick-height (the
   connector line's own length) are separate custom properties on
   purpose — tune the gap without the tick auto-resizing, or vice versa.
   The tick is anchored to the BOTTOM of the gap (right above this
   item's number), so a shorter tick just leaves more empty space above
   it rather than stretching to fill the gap. */
.why-item {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 20px;
  width: 620px;
  max-width: 100%;
  --why-gap: 28px;
  margin-top: var(--why-gap);
  margin-left: calc(var(--why-i, 0) * clamp(24px, 8vw, 150px));
  padding-bottom: 20px;
}

.why-item:first-child { margin-top: 0; }

.why-item:nth-child(1) { --why-i: 0; }
.why-item:nth-child(2) { --why-i: 1; }
.why-item:nth-child(3) { --why-i: 2; }
.why-item:nth-child(4) { --why-i: 3; }
.why-item:nth-child(5) { --why-i: 4; }

/* The baseline is a separate element (not border-bottom) so it can be
   animated as a left-to-right "draw" when the panel becomes active,
   scaleX(0) -> scaleX(1) from a left transform-origin, staggered per
   item so they draw one after another rather than all at once. */
.why-item-line {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: rgba(255, 255, 255, 0.15);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.7s ease;
}

.panel-why.is-active .why-item:nth-child(1) .why-item-line { transition-delay: 0.1s; }
.panel-why.is-active .why-item:nth-child(2) .why-item-line { transition-delay: 0.3s; }
.panel-why.is-active .why-item:nth-child(3) .why-item-line { transition-delay: 0.5s; }
.panel-why.is-active .why-item:nth-child(4) .why-item-line { transition-delay: 0.7s; }
.panel-why.is-active .why-item:nth-child(5) .why-item-line { transition-delay: 0.9s; }

.panel-why.is-active .why-item-line {
  transform: scaleX(1);
}

/* Vertical tick connecting this item up toward the previous one's
   underline. Independent of --why-gap: it's bottom-anchored at the top
   of this item, so changing --why-gap moves the tick's starting point
   with it but never stretches/shrinks the tick itself, and changing
   --why-tick-height never affects item spacing. */
.why-item:not(:first-child) {
  /* How far past this item's own top edge (i.e. into the number) the
     tick continues, on top of spanning the --why-gap above it. */
  --why-tick-overshoot: 100px;
}

.why-item:not(:first-child)::before {
  content: "";
  position: absolute;
  left: -16px;
  top: calc(-1 * var(--why-gap));
  width: 1px;
  height: calc(var(--why-gap) + var(--why-tick-overshoot));
  background: rgba(255, 255, 255, 0.15);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.7s ease;
}

.panel-why.is-active .why-item:nth-child(2)::before { transition-delay: 0.3s; }
.panel-why.is-active .why-item:nth-child(3)::before { transition-delay: 0.5s; }
.panel-why.is-active .why-item:nth-child(4)::before { transition-delay: 0.7s; }
.panel-why.is-active .why-item:nth-child(5)::before { transition-delay: 0.9s; }

.panel-why.is-active .why-item:not(:first-child)::before {
  transform: scaleY(1);
}

.why-number {
  flex-shrink: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 4vw, 4rem);
  line-height: 1;
  color: rgba(255, 255, 255, 0.35);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.why-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.3rem, 2vw, 1.9rem);
  line-height: 1.3;
  color: var(--text);
  max-width: 20ch;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.panel-why.is-active .why-item:nth-child(1) .why-number,
.panel-why.is-active .why-item:nth-child(1) .why-title { transition-delay: 0.1s; }
.panel-why.is-active .why-item:nth-child(2) .why-number,
.panel-why.is-active .why-item:nth-child(2) .why-title { transition-delay: 0.3s; }
.panel-why.is-active .why-item:nth-child(3) .why-number,
.panel-why.is-active .why-item:nth-child(3) .why-title { transition-delay: 0.5s; }
.panel-why.is-active .why-item:nth-child(4) .why-number,
.panel-why.is-active .why-item:nth-child(4) .why-title { transition-delay: 0.7s; }
.panel-why.is-active .why-item:nth-child(5) .why-number,
.panel-why.is-active .why-item:nth-child(5) .why-title { transition-delay: 0.9s; }

.panel-why.is-active .why-number,
.panel-why.is-active .why-title {
  opacity: 1;
  transform: translateY(0);
}

@media (max-width: 700px) {
  /* .why-list's -60px margin-top exists to pull the staircase list up
     under the eyebrow on desktop — combined with the eyebrow's own
     already-reduced mobile gap (.section-eyebrow's 64px margin-bottom
     at ≤900px), that left only ~4px between "WHY CHOOSE US" and the
     first item here, reading as touching/overlapping. */
  .why-list {
    margin-top: 24px;
  }

  .why-item {
    margin-left: 0;
    max-width: 100%;
  }
  .why-item:not(:first-child)::before {
    display: none;
  }
}

/* Clients Say panel (Figma node 156:5919) — a coverflow-style carousel:
   one testimonial card centered and fully opaque, the rest laid out
   either side, shrinking/fading/dimming the further they sit from
   center. Sizing (full-bleed, no max-width) lives on
   .panel-section-inner--clients now that this is its own <section>. */
.clients-carousel {
  position: relative;
  width: 100%;
  padding: 10px 0;
}

/* Height is set inline by script.js, measured from the active card's
   real content height (the cards are position:absolute so they don't
   otherwise push this box taller) — this is just a pre-JS fallback. */
.clients-track {
  position: relative;
  width: 100%;
  min-height: 460px;
}

/* Position/scale/opacity are computed per-card in script.js (as inline
   styles, from each card's signed distance from the active index) since
   CSS has no reliable cross-browser abs() yet — this file only owns the
   transition and the static look. */
.client-card {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 500px;
  max-width: 90vw;
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  background: rgba(4, 7, 11, 0.5);
  border-radius: 28px;
  pointer-events: none;
  transition: transform 0.6s ease, opacity 0.6s ease, background 0.6s ease;
}

.client-card.is-active {
  background: rgb(6, 14, 27);
  pointer-events: auto;
}

/* Faint glowing rim lines top and bottom, same technique as
   .product-card's — only on the centered/active card. */
.client-card.is-active::before,
.client-card.is-active::after {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  height: 6px;
  background: linear-gradient(90deg, transparent, rgba(120, 150, 255, 0.55), transparent);
  filter: blur(3px);
  pointer-events: none;
}

.client-card.is-active::before { top: -2px; }
.client-card.is-active::after { bottom: -2px; }

.client-card-head {
  display: flex;
  align-items: center;
  gap: 16px;
}

.client-avatar {
  flex-shrink: 0;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  object-fit: cover;
  background: #fff;
}

.client-card-id {
  display: flex;
  flex-direction: column;
  gap: 13px;
  min-width: 0;
}

.client-name {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 18px;
  color: var(--text);
}

.client-role {
  margin: 0;
  font-size: clamp(0.9rem, 1.2vw, 1.25rem);
  color: #b4b4b4;
}

.client-card-divider {
  height: 1px;
  background: var(--border-soft);
}

.client-card-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.client-stars {
  width: 150px;
  height: auto;
}

.client-review {
  margin: 0;
  font-size: clamp(0.9rem, 0.1vw, 1.1rem);
  line-height: 1.6;
  color: #bdbdbd;
  /* Caps at 6 lines (line-height is a unitless multiplier of this
     element's own font-size, so 1.6em == 1 line here) — anything
     longer scrolls inside the paragraph itself instead of growing the
     card, which keeps every testimonial's card the same height. */
  max-height: calc(1.6em * 6);
  overflow-y: auto;
  padding-right: 4px;
}

.client-review::-webkit-scrollbar {
  width: 5px;
}

.client-review::-webkit-scrollbar-track {
  background: transparent;
}

.client-review::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.25);
  border-radius: 3px;
}

.clients-carousel-dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 12px;
}

.clients-carousel-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
  cursor: pointer;
  transition: background 0.25s ease, transform 0.25s ease;
}

.clients-carousel-dot.is-active {
  background: var(--accent);
  transform: scale(1.3);
}

@media (max-width: 900px) {
  .client-card {
    width: 560px;
  }
}

@media (max-width: 700px) {
  .client-card {
    max-width: 94vw;
    padding: 16px;
    gap: 16px;
  }

  .client-avatar {
    width: 64px;
    height: 64px;
  }

  .client-card-head {
    gap: 12px;
  }

  .client-card-id {
    gap: 8px;
  }

  .client-stars {
    width: 120px;
  }
}

/* FAQ panel (Figma node 156:10665) — an accordion list (765px, one item
   open at a time) beside a "didn't find the answer" CTA card that
   reuses the same pill/dot component as the Products panel's "All
   Products" pill (.product-nav-pill), just wider and fully rounded. */
/* align-items isn't flex-end here on purpose — that would tie the CTA's
   position to the list's live rendered height, so it'd visibly slide
   down every time an accordion item opens. Instead it stays
   flex-start, and script.js sets a one-time margin-top computed from
   the list's *collapsed* height so the CTA lands in the same lower
   spot without moving when items expand. */
.faq-layout {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 120px;
  max-width: 1180px;
  margin: 0 auto;
}

/* Fixed width, no grow or shrink, above 1400px — with flex:1 (or a
   basis that only just fit the 1180px panel alongside the CTA column)
   the list ate any extra room before the gap could grow, so bumping
   the gap value alone had no visible effect. Sized to comfortably
   leave the full 120px gap free rather than depending on shrink math.
   Below 1400px it switches to actually shrinking (see media query
   below) so the question text can wrap instead of forcing the row
   past the viewport. */
.faq-list {
  flex: 0 0 700px;
  max-width: 700px;
  border-top: 1px solid var(--border-soft);
}

.faq-item {
  border-bottom: 1px solid var(--border-soft);
}

.faq-question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  width: 100%;
  padding: 24px 0;
  background: none;
  border: none;
  text-align: left;
  color: #bdbdbd;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.1rem, 1.6vw, 1.5rem);
  cursor: pointer;
}

/* Without min-width:0, a flex item's default min-width:auto refuses to
   shrink below its own single-line text width — so on narrow screens
   the question text held its full width instead of wrapping, pushing
   .faq-toggle-icon off the right edge of the viewport entirely. */
.faq-question-text {
  flex: 1 1 auto;
  min-width: 0;
}

.faq-toggle-icon {
  position: relative;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #191919;
}

.faq-bar {
  position: absolute;
  left: 50%;
  top: 50%;
  background: var(--accent);
  border-radius: 1px;
  transition: transform 0.3s ease;
}

.faq-bar--h {
  width: 14px;
  height: 2px;
  transform: translate(-50%, -50%);
}

.faq-bar--v {
  width: 2px;
  height: 14px;
  transform: translate(-50%, -50%) scaleY(1);
}

.faq-item.is-open .faq-bar--v {
  transform: translate(-50%, -50%) scaleY(0);
}

.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.4s ease;
}

.faq-answer-text {
  margin: 0;
  padding-bottom: 24px;
  color: #bdbdbd;
  font-size: clamp(0.9rem, 1.1vw, 1.25rem);
  line-height: 1.6;
}

.faq-item.is-open .faq-answer {
  max-height: 400px;
}

.faq-cta {
  flex-shrink: 0;
  width: 343px;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: 37px;
}

.faq-cta-text {
  margin: 0;
  color: #bdbdbd;
  font-weight: 500;
  font-size: clamp(1.2rem, 1.8vw, 1.625rem);
  line-height: 1.35;
}

.faq-cta-pill {
  width: 343px;
  max-width: 100%;
  border-radius: 29px;
  font-size: clamp(18px, 1.6vw, 24px);
  text-decoration: none;
}

/* .product-nav-pill's label is normally a bare text node, which as a
   flex item defaults to min-width:auto — refusing to shrink below its
   own single-line width, the same overflow bug .faq-question-text had.
   Wrapped in its own span here so it can be constrained instead of
   forcing the pill wider than the screen on narrow viewports. */
.faq-cta-pill-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Between the point the row gets tight and the 900px stack breakpoint
   below, the list was still holding a fixed 700px (flex-shrink:0) with
   a fixed 120px gap beside it — the pair no longer fit the narrowing
   container, so the row overflowed instead of the question text
   wrapping tighter like it already does once stacked at ≤900px.
   Letting the list actually shrink (flex-shrink + min-width:0, the
   same fix needed anywhere a flex item's text should wrap) and easing
   the gap down fixes both. */
@media (max-width: 1400px) {
  .faq-layout {
    gap: clamp(48px, 8vw, 120px);
  }

  .faq-list {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 700px;
  }
}

@media (max-width: 900px) {
  .faq-layout {
    flex-direction: column;
    align-items: stretch;
    gap: 64px;
  }

  /* flex:0 0 700px on .faq-list sets its *main-axis* size — width in
     the row layout above, but once flex-direction switches to column
     here the main axis is vertical, so that same rule would otherwise
     force a fixed 700px height instead of a width. Reset the basis
     back to auto and let width come from the stretch alignment. */
  .faq-list {
    flex-basis: auto;
    max-width: 100%;
  }

  .faq-cta {
    width: 100%;
    max-width: 420px;
  }

  .faq-cta-pill {
    width: 320px;
    height: 52px;
    max-width: 420px;
  }

  .faq-question-text {
    max-width: 85%;
  }
}

@media (max-width: 700px) {
  .faq-layout {
    gap: 40px;
  }

  .faq-question {
    padding: 18px 0;
    gap: 16px;
    font-size: 14px;
  }

  .faq-question-text {
    max-width: 75%;
  }

  .faq-answer-text {
    font-size: 14px;
  }

  .faq-toggle-icon {
    width: 32px;
    height: 32px;
  }

  .faq-cta {
    gap: 20px;
  }

  .faq-cta-text {
    font-size: clamp(0.9rem, 4vw, 1.4rem);
  }

  .faq-cta-pill {
    height: 46px;
    width: 290px;
    padding: 0 14px 0 18px;
    font-size: 16px;
  }
}

/* Our Services bento grid */
.services-grid {
  display: grid;
  grid-template-columns: minmax(0, 792fr) minmax(0, 400fr) minmax(0, 422fr);
  grid-template-rows: minmax(260px, 240fr) minmax(170px, 270fr);
  gap: 14px;
  width: 100%;
}

.service-card--app { grid-column: 1; grid-row: 1 / 3; }
.service-card--web { grid-column: 2 / 4; grid-row: 1; }
.service-card--marketing { grid-column: 2; grid-row: 2; }
.service-card--design { grid-column: 3; grid-row: 2; }

.service-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 20px;
  padding: 28px 24px;
  background: rgba(244, 241, 234, 0.03);
  border: 1px solid var(--border-soft);
  border-radius: 28px;
  overflow: hidden;
  opacity: 0;
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.panel-services.is-active .service-card {
  opacity: 1;
  transform: translate(0, 0) !important;
}

.service-card--from-left { transform: translateX(-70px); }
.service-card--from-right { transform: translateX(70px); }
.service-card--from-bottom { transform: translateY(70px); }

.panel-services.is-active .service-card--web { transition-delay: 0.08s; }
.panel-services.is-active .service-card--marketing { transition-delay: 0.16s; }
.panel-services.is-active .service-card--design { transition-delay: 0.24s; }

.service-card h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.1rem, 1.6vw, 1.5rem);
  color: #ededed;
}

.service-card-art {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 0;
}

/* App Development card art (Figma node 93:572) — a phone mockup with a
   simple "smiling face" screen, set against 3 dashed vertical lines that
   bleed above/below it, clipped by the card's own bounds. */
.service-card-art--phone {
  position: relative;
  overflow: visible;
}

/* Each "dash" is really a repeating streak (Figma's Line 5 asset: a thin
   66px stroke that fades from solid white to transparent), tiled every
   119px — not a hard-edged dash. The 3 lines sit at different vertical
   offsets in the design (93:573/574/575 start at -227/-185/-234px above
   the card), so their fade rhythm is staggered rather than in lockstep;
   background-position reproduces that stagger. */
.service-card-dash {
  position: absolute;
  top: -40%;
  bottom: -40%;
  width: 1.5px;
  background-image: repeating-linear-gradient(
    to bottom,
    rgba(237, 237, 237, 0.85) 0,
    rgba(237, 237, 237, 0) 66px,
    transparent 66px,
    transparent 119px
  );
  background-position-y: var(--dash-offset, 0);
}

.service-card-dash--1 { left: 32%; --dash-offset: 11px; }
.service-card-dash--2 { left: 50%; --dash-offset: 53px; }
.service-card-dash--3 { left: 70%; --dash-offset: 4px; }

@media (prefers-reduced-motion: no-preference) {
  .service-card-dash {
    animation: dashScrollUp 0.6s linear infinite;
  }

  /* One full pattern period (119px) so the loop is seamless; each dash
     keeps its own stagger via --dash-offset as the animation's start. */
  @keyframes dashScrollUp {
    from { background-position-y: var(--dash-offset, 0); }
    to { background-position-y: calc(var(--dash-offset, 0) - 119px); }
  }
}

.service-card-phone {
  position: relative;
  width: 165px;
  height: 276px;
  border: 4px solid #e6e6e6;
  border-radius: 20px;
  background: #0b0f1e;
  box-shadow: 10px 9px 0 0 rgba(43, 43, 43, 0.4);
  overflow: hidden;
}

@media (prefers-reduced-motion: no-preference) {
  .service-card-phone {
    animation: phoneFloat 3.2s ease-in-out infinite;
  }

  @keyframes phoneFloat {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-14px); }
  }
}

.service-card-phone-notch {
  position: absolute;
  top: 9px;
  left: 64px;
  width: 36px;
  height: 8px;
  border-radius: 999px;
  background: #ededed;
}

.service-card-eye {
  position: absolute;
  top: 120px;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  border: 2.5px solid rgba(237, 237, 237, 0.6);
}

.service-card-eye--left { left: 40px; }
.service-card-eye--right { left: 103px; }

.service-card-blush {
  position: absolute;
  top: 125px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #7a3232;
}

.service-card-blush--left { left: 19px; }
.service-card-blush--right { left: 133px; }

.service-card-smile {
  position: absolute;
  top: 140px;
  left: 71px;
  width: 21px;
  height: 11px;
  border: 2.5px solid rgba(237, 237, 237, 0.6);
  border-top: none;
  border-radius: 0 0 21px 21px;
}

/* Web Development card art (Figma node 93:587) — 4 nested "browser
   window" outlines cascading toward the bottom-right, each with its own
   traffic-light dots; the innermost one also holds 2 content placeholder
   bars. Positions/insets below are derived from the design's absolute
   coordinates, expressed as percentages of each window's own parent so
   the whole thing scales with the card. */
/* max-width raised from the art's own natural size (480px, which
   only reaches ~166px tall via the aspect-ratio below) so it can grow
   into the full 256px max-height instead of stalling far short of it
   — the Web card's grid slot is comfortably wider than that on
   desktop, and the leftover 480px cap was leaving a large empty gap
   below the "Web Development" label as the flex column centered a
   much-shorter-than-expected art block within the tall card. */
.service-card-art--web {
  position: relative;
  width: 100%;
  max-height: 256px;
  max-width: 325px;
  aspect-ratio: 868 / 300;
}

.service-card-webwin {
  position: absolute;
  inset: 0;
  background: #0b0f1e;
  border: 1.5px solid rgba(237, 237, 237, 0.7);
  border-radius: 14px;
}

.service-card-webwin--2 { inset: 10% 2% 3% 11%; border-radius: 12px; }
.service-card-webwin--3 { inset: 11% 2% 4% 12%; border-radius: 10px; }
.service-card-webwin--4 { inset: 17% 3% 5% 18%; border-radius: 8px; }

/* Figma's Frame 37 <-> Frame 38 component states (node 72:1403): the
   nested windows cascade back out to Frame 37's tucked-in arrangement,
   then grow past their own parent's edges (negative insets) into Frame
   38's "front window comes forward" arrangement, and back — looping.
   Each window's Frame 38 inset is computed the same way as its Frame 37
   one: relative to its immediate parent window, not the card. */
@media (prefers-reduced-motion: no-preference) {
  .service-card-webwin--2 {
    animation: webWin2Cycle 3.5s ease-in-out infinite;
  }
  .service-card-webwin--3 {
    animation: webWin3Cycle 3.5s ease-in-out infinite;
  }
  .service-card-webwin--4 {
    animation: webWin4Cycle 3.5s ease-in-out infinite;
  }

  @keyframes webWin2Cycle {
    0%, 35% { inset: 10% 2% 3% 11%; }
    50%, 85% { inset: -3.8% 1.6% 2.9% -2.4%; }
    100% { inset: 10% 2% 3% 11%; }
  }
  @keyframes webWin3Cycle {
    0%, 35% { inset: 11% 2% 4% 12%; }
    50%, 85% { inset: -3.4% 1.8% 3.1% -2.1%; }
    100% { inset: 11% 2% 4% 12%; }
  }
  @keyframes webWin4Cycle {
    0%, 35% { inset: 17% 3% 5% 18%; }
    50%, 85% { inset: -3.4% 2% 3.4% -2%; }
    100% { inset: 17% 3% 5% 18%; }
  }
}

.service-card-webdots {
  position: absolute;
  top: 8%;
  left: 6%;
  display: flex;
  gap: 5px;
}

.service-card-webdot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
}

.service-card-webwin--2 .service-card-webdot { width: 6px; height: 6px; }
.service-card-webwin--3 .service-card-webdot { width: 5.2px; height: 5.2px; }
.service-card-webwin--4 .service-card-webdot { width: 4.4px; height: 4.4px; }

.service-card-webdot--green { background: #6fcf67; }
.service-card-webdot--amber { background: #f2c94c; }
.service-card-webdot--red { background: #eb5757; }

.service-card-webbar {
  position: absolute;
  left: 7%;
  width: 86%;
  border-radius: 4px;
  background: rgba(237, 237, 237, 0.08);
}

.service-card-webbar--top { top: 31%; height: 14%; }
.service-card-webbar--bottom { top: 54%; height: 34%; }

/* Frame 38's window content isn't just a bigger version of Frame 37's —
   the single full-width bottom bar splits into a small left block plus a
   large right block (Figma Rectangle 7 + Rectangle 5). The existing
   bottom bar animates down into the "left block" role, and a new element
   fades in for the "right block", both synced to the window-frame cycle. */
.service-card-webbar--right {
  top: 54.2%;
  height: 34.57%;
  left: 31.44%;
  width: 61.31%;
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .service-card-webbar--top {
    animation: webBarTopCycle 3.5s ease-in-out infinite;
  }
  .service-card-webbar--bottom {
    animation: webBarBottomCycle 3.5s ease-in-out infinite;
  }
  .service-card-webbar--right {
    animation: webBarRightCycle 3.5s ease-in-out infinite;
  }

  @keyframes webBarTopCycle {
    0%, 35% { top: 31%; height: 14%; left: 7%; width: 86%; }
    50%, 85% { top: 21.8%; height: 19.62%; left: 7.28%; width: 86.03%; }
    100% { top: 31%; height: 14%; left: 7%; width: 86%; }
  }
  @keyframes webBarBottomCycle {
    0%, 35% { top: 54%; height: 34%; left: 7%; width: 86%; }
    50%, 85% { top: 54.2%; height: 34.57%; left: 6.72%; width: 17.18%; }
    100% { top: 54%; height: 34%; left: 7%; width: 86%; }
  }
  @keyframes webBarRightCycle {
    0%, 35% { opacity: 0; }
    50%, 85% { opacity: 1; }
    100% { opacity: 0; }
  }
}

/* Digital Marketing card art — infinite horizontal carousel/orbit of 5
   platform-icon badges (Instagram 78:1934, Facebook 78:1955, SEO 78:1816,
   Review 78:1844, YouTube 78:1780). All 5 continuously drift right-to-left
   through 5 evenly-spaced slots (+2..-2) and wrap, in the rotation order
   shown by the component states at node 78:2675. Depth is simulated by
   scale/opacity tied to slot position: the center slot is largest and
   fully opaque, each slot further out shrinks and fades — a coverflow-
   style focus shift rather than a hard cut between icons. */
.service-card-art--marketing {
  position: relative;
  width: 150px;
  height: 68px;
}

.service-card-marketing-icon {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 52px;
  height: 52px;
  transform: translate(calc(-50% + 90px), -50%) scale(0.55);
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .service-card-marketing-icon {
    animation: marketingOrbit 10s linear infinite;
  }

  .service-card-marketing-icon:nth-child(1) { animation-delay: 0s; }
  .service-card-marketing-icon:nth-child(2) { animation-delay: -2s; }
  .service-card-marketing-icon:nth-child(3) { animation-delay: -4s; }
  .service-card-marketing-icon:nth-child(4) { animation-delay: -6s; }
  .service-card-marketing-icon:nth-child(5) { animation-delay: -8s; }

  @keyframes marketingOrbit {
    0%   { transform: translate(calc(-50% + 90px), -50%) scale(0.55); opacity: 0; z-index: 1; }
    20%  { transform: translate(calc(-50% + 45px), -50%) scale(0.82); opacity: 0.55; z-index: 1; }
    39%  { z-index: 1; }
    40%  { transform: translate(-50%, -50%) scale(1.2); opacity: 1; z-index: 5; }
    41%  { z-index: 1; }
    60%  { transform: translate(calc(-50% - 45px), -50%) scale(0.82); opacity: 0.55; z-index: 1; }
    80%  { transform: translate(calc(-50% - 90px), -50%) scale(0.55); opacity: 0; z-index: 1; }
    100% { transform: translate(calc(-50% + 90px), -50%) scale(0.55); opacity: 0; z-index: 1; }
  }
}

@media (prefers-reduced-motion: reduce) {
  .service-card-marketing-icon { opacity: 0; }
  .service-card-marketing-icon:first-child {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1.2);
  }
}

/* Product Design card art — 3 dashed rings + 3 UI/UX/CX pill badges
   (Figma node 93:591 / 484:6947), exported as one flat SVG rather than
   built from separate ring/pill elements, so it scales responsively
   with a single width/height instead of per-element percentage math. */
.service-card-art--design {
  position: relative;
  width: 100%;
  max-width: 180px;
  aspect-ratio: 1 / 1;
}

.service-card-design-img {
  display: block;
  width: 100%;
  height: 100%;
}

/* Tablet: 2x2 grid (App/Marketing on top, Web/Design below) rather
   than jumping straight from the 3-column desktop layout to a single
   stacked column — the desktop column spans (.service-card--web
   spanning 2 columns, .service-card--app spanning 2 rows) don't fit a
   2-column grid, so every card gets an explicit re-placement here. */
@media (max-width: 900px) and (min-width: 641px) {
  .services-grid {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: none;
  }
  .service-card--app { grid-column: 1; grid-row: 1; }
  .service-card--marketing { grid-column: 2; grid-row: 1; }
  .service-card--web { grid-column: 1; grid-row: 2; }
  .service-card--design { grid-column: 2; grid-row: 2; }
}

/* Phone: single carousel across all 4 cards, one at a time — stacked
   in the same grid cell (same technique as .product-card-stack) with
   .services-carousel-dots below it. JS (script.js) drives which card
   is .is-active on a timer, by dot click, and by swipe; see the
   comment there for why. The grid cell itself auto-sizes to the
   tallest card since opacity (not display) is what hides the rest,
   so they still take part in layout. */
@media (max-width: 640px) {
  .services-grid {
    grid-template-columns: 1fr;
    grid-template-rows: none;
  }
  .service-card--app,
  .service-card--web,
  .service-card--marketing,
  .service-card--design {
    grid-column: 1;
    grid-row: 1;
  }

  /* Only opacity, not transform — .panel-services.is-active
     .service-card already forces transform:translate(0,0) with
     !important for the entrance animation, so touching transform
     here would silently lose to that rule. */
  .panel-services.is-active .service-card:not(.is-active) {
    opacity: 0;
    pointer-events: none;
  }

  .services-carousel-dots {
    display: flex;
    justify-content: center;
    margin-top: 24px;
  }
}

@media (max-width: 640px) {
  .panel-trusted { margin-left: 0; }
}

.stat p {
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--text-muted);
  margin: 0;
  max-width: 30ch;
  min-width: 0;
  flex: 1 1 180px;
}

/* Below the width where the deliberate desktop indent (see .panel-trusted
   above) still leaves real slack space, center the block and its stat
   content instead of reading as lopsided. Eyebrow stays left-aligned,
   matching every other section. Placed after every other rule touching
   .panel-trusted so it wins the equal-specificity, source-order tiebreak. */
@media (max-width: 1750px) {
  .panel-trusted {
    margin-left: auto;
    margin-right: auto;
  }

  .stat {
    text-align: center;
  }

  .stat-figure {
    justify-content: center;
  }
}

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

/* Footer (Figma node 163:3705) — a huge PINNACLE wordmark (exported as
   one SVG, same letterforms as the header logo just scaled way up)
   over a dark vertical-gradient backdrop, with 4 columns (contact,
   navigation, social, address) and a centered copyright line below. */
.site-footer {
  position: relative;
  background: linear-gradient(180deg, #080e16 0%, #000000 90%);
  padding: 64px var(--container-pad) 48px;
  overflow: clip;
}

.footer-wordmark {
  max-width: 1702px;
  margin: 0 auto 64px;
}

.footer-wordmark-img {
  display: block;
  width: 100%;
  height: auto;
}

.footer-columns {
  max-width: 1450px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 40px;
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: 17px;
}

.footer-col--nav,
.footer-col--address {
  gap: 12px;
}

.footer-col-label {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 16px;
  color: #737373;
}

.footer-col-tick {
  width: 30px;
  height: 1px;
  background: rgba(190, 190, 190, 0.5);
}

.footer-col a,
.footer-contact-phone,
.footer-contact-email a,
.footer-address-text {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.4;
  color: #bebebe;
  text-decoration: none;
}

.footer-col a {
  transition: color 0.2s ease;
}

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

.footer-col--nav a {
  font-size: 16px;
}

/* The current page's own link — dimmed to the same muted tone as the
   "Navigation" label above it, reading as a plain "you are here" marker
   rather than another clickable option. Kept dim on hover too (instead
   of picking up .footer-col a:hover's brighten) so it stays visually
   settled as the active one even if the cursor passes over it. */
.footer-col--nav a.is-current,
.footer-col--nav a.is-current:hover {
  color: #737373;
}

.footer-contact-phone,
.footer-address-text {
  margin: 0;
}

.footer-address-text {
  font-size: 16px;
}

.footer-copyright {
  margin: 64px 0 0;
  text-align: center;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: clamp(16px, 1.6vw, 16px);
  color: #939393;
}

@media (max-width: 900px) {
  .footer-columns {
    gap: 32px 24px;
  }

  .footer-col {
    flex: 1 1 40%;
  }
}

@media (max-width: 640px) {
  .site-footer {
    padding: 48px var(--container-pad) 32px;
  }

  .footer-wordmark {
    margin-bottom: 40px;
  }

  .footer-col {
    flex: 1 1 100%;
  }

  .footer-col--nav a {
    font-size: 16px;
  }

  .footer-address-text {
    font-size: 16px;
  }
}

/* ==========================================================================
   Responsive — tablet
   ========================================================================== */

/* ==========================================================================
   Responsive — mobile nav
   ========================================================================== */

@media (max-width: 860px) {
  .header-divider { display: none; }

  .nav-toggle { display: flex; }

  .main-nav {
    position: fixed;
    top: var(--header-h);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    background: var(--bg-panel);
    border-bottom: 1px solid var(--border-soft);
    padding: 16px var(--container-pad) 24px;
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s ease;
  }

  .main-nav.is-open {
    opacity: 1;
    transform: translateY(0);
    visibility: visible;
  }

  .nav-link { padding: 10px 0; width: 100%; }
  .nav-dropdown { width: 100%; }
  .nav-dropdown-menu { position: static; border: none; padding: 0 0 0 12px; opacity: 1; visibility: visible; transform: none; display: none; }
  .nav-dropdown-menu.is-open { display: flex; }

  .header-cta { display: none; }

  .nav-mobile-cta {
    display: block;
    width: 100%;
    margin-top: 12px;
    text-align: center;
  }
}

@media (max-width: 640px) {
  .stats-row { grid-template-columns: 1fr; }
  .stat-figure { flex-wrap: wrap; }
  .hero-actions { gap: 20px 32px; }
  .stats-inner { margin-left: 0; }
  .section-eyebrow-badge { padding: 10px 20px; }
}

/* ==========================================================================
   Products page (products.html, Figma node 163:5420) — a standalone page
   (not part of the homepage's wheel-snap journey), so it gets its own
   simple top bar (breadcrumb + CTA pill, no full nav — Figma explicitly
   hides the nav-links row for this page) instead of the shared
   .site-header, plus a hero (kicker + huge title + subtitle) and a
   free-scrolling row of every product card.
   ========================================================================== */
/* Transparent over the hero at the top of the page; gains a solid
   background + hairline border (.is-scrolled, toggled in
   js/products.js) once scrolled, since it's position:fixed and stays
   pinned over whatever's scrolling underneath it the rest of the way
   down the page (Figma node 241:6110 shows it still pinned at the
   footer). */
.products-topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 28px var(--container-pad);
  background: transparent;
  transition: background 0.3s ease, box-shadow 0.3s ease;
}

.products-topbar.is-scrolled {
  background: #0d1117;
  box-shadow: 0 1px 0 rgba(139, 146, 160, 0.3);
}

.products-breadcrumb {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-display);
  font-size: clamp(15px, 1.4vw, 20px);
  color: #a6a6a6;
}

.products-breadcrumb a {
  color: inherit;
  text-decoration: none;
}

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

.products-breadcrumb .is-current {
  font-weight: 700;
  color: var(--accent);
}

/* .products-topbar is fixed (out of flow) and its rendered height
   varies by breakpoint (it wraps to two rows on narrow screens), so
   rather than guess that height per breakpoint here, js/products.js
   measures it and sets this section's padding-top (as --topbar-h)
   to compensate — otherwise the hero content would sit underneath it. */
.products-hero {
  position: relative;
  display: flex;
  justify-content: center;
  padding: calc(var(--topbar-h, 114px) + 24px) var(--container-pad) 24px;
  overflow: clip;
  background: #0d1117;
  /* Entrance: slides down from above, fading in — .is-revealed is
     added in js/products.js shortly after load. */
  opacity: 0;
  transform: translateY(-60px);
  transition: opacity 0.8s ease, transform 0.8s ease;
}

.products-hero.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Kicker/title/subtitle are left-aligned to a shared edge (NOT each
   individually centered via text-align — Figma has the subtitle's own
   left edge flush with the title's, not centered under its shorter
   width), and it's this whole block that's centered as a unit via the
   parent's justify-content:center. */
.products-hero-inner {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Careers' hero title+subtitle (Figma node 231:9072) are centered as
   a block, unlike the other interior pages' left-aligned-then-centered
   pattern above. */
.products-hero-inner--center {
  align-items: center;
  text-align: center;
}

.products-kicker {
  height: clamp(12px, 1.4vw, 16px);
  width: auto;
  margin-bottom: 12px;
}

.products-title {
  position: relative;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3.5rem, 9vw, 7rem);
  line-height: 1;
  color: #a6a6a6;
}

.products-subtitle {
  position: relative;
  margin: 20px 0 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 3.2vw, 3.125rem);
  color: var(--text);
}

/* Smaller than the bare .products-subtitle default — used by both
   Work's full-sentence subtitle and Products' "SAAS & MOBILE APPS"
   kicker line (About's hero has no subtitle at all). */
.products-subtitle--sm {
  margin-top: 12px;
  font-size: clamp(1rem, 1.6vw, 1.625rem);
  font-weight: 400;
}

/* Products' subtitle centers itself under PRODUCTS/the kicker mark
   rather than sitting left-flush with them like Work's does — the
   rest of .products-hero-inner's children stay flex-start (see the
   comment above .products-hero-inner). align-self here (not
   text-align) so it's the subtitle's own shrink-to-fit box that
   moves, not just the text inside a full-width box. */
.products-subtitle--center {
  align-self: center;
}

.products-list {
  position: relative;
  overflow: clip;
  padding: 64px 0 96px;
  /* Entrance: slides up from below, fading in, a beat after the hero
     above it (.is-revealed added in js/products.js). */
  opacity: 0;
  transform: translateY(60px);
  transition: opacity 0.8s ease 0.15s, transform 0.8s ease 0.15s;
}

/* Ambient glow (Figma node 231:9200) sits at the TOP of the section
   below .products-hero, not inside the hero itself — the hero stays
   plain/flat and this section's own top edge is where the radial
   gradient starts. Reused on .about-statement/.careers-apply below,
   whichever page's hero this happens to precede. */
.products-list::before {
  content: "";
  position: absolute;
  inset: -10% -10% auto -10%;
  height: 700px;
  background: radial-gradient(ellipse 60% 60% at 50% 0%, rgba(0, 16, 119, 0.55), transparent 70%);
  pointer-events: none;
}

.products-list.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Free-scrolling row (native overflow-x, no JS) — every product card at
   its natural width rather than cramming them into a fixed grid, with a
   right-edge fade hinting there's more to scroll to, matching the
   design's partially-faded trailing card. */
.products-scroll {
  display: flex;
  gap: 32px;
  overflow-x: auto;
  padding: 8px var(--container-pad) 80px;
  scrollbar-width: none;
  -ms-overflow-style: none;
  mask-image: linear-gradient(90deg, black 92%, transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, black 92%, transparent 100%);
}

.products-scroll::-webkit-scrollbar {
  display: none;
}

.products-scroll .product-card {
  flex: 0 0 auto;
  width: 575px;
}

/* Wraps .products-scroll so the prev/next buttons below can sit over
   its edges without becoming scrollable content themselves — paging
   controls for js/products.js's arrow-click scrollBy, not a mouse-wheel
   hijack (see the comment there for why). */
.products-scroll-wrap {
  position: relative;
}

.products-scroll-arrow {
  position: absolute;
  top: 40%;
  transform: translateY(-50%);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease, opacity 0.2s ease;
}

.products-scroll-arrow svg {
  width: 20px;
  height: 20px;
}

.products-scroll-arrow:hover:not(:disabled) {
  background: var(--accent);
}

.products-scroll-arrow:disabled {
  opacity: 0.3;
  cursor: default;
}

/* A small fixed inset rather than var(--container-pad) — that scales
   up to 217px on wide screens (the page's normal side gutter), which
   leaves a 48px button stranded far from the row's actual edge with a
   wide dead gap beyond it instead of sitting snug against the cards. */
.products-scroll-arrow--prev { left: 24px; }
.products-scroll-arrow--next { right: 24px; }

/* Nothing to page through (e.g. a 2-card Other Products row that
   already fits at this width) — hide both arrows instead of leaving
   them permanently disabled. Toggled in js/products.js. */
.products-scroll-wrap--no-overflow .products-scroll-arrow {
  display: none;
}

@media (max-width: 640px) {
  /* Touch swipe is the natural way to page the row at this width, and
     there's no room for a 48px circle beside the card without
     overlapping it. */
  .products-scroll-arrow {
    display: none;
  }
}

/* Work page — a centered 2-up grid instead of .products-scroll's
   horizontal carousel (only a couple of case studies exist so far,
   not a long scrollable row). Column width matches .product-card's
   own 575px cap: (1294 - 144 gap) / 2 = 575, so the grid's max-width
   plus gap reproduce Figma's spacing exactly at desktop width. */
.work-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  justify-items: center;
  gap: 32px 144px;
  /* max-width and side-gutter both apply to the same box (border-box),
     so express the cap as a width calc instead of max-width + padding
     — otherwise the padding eats into the 1294px cap and the columns
     (and therefore the 575px cards inside them) end up narrower than
     the design. */
  width: min(1294px, calc(100% - 2 * var(--container-pad)));
  margin: 0 auto;
}

@media (max-width: 900px) {
  .products-hero {
    padding: calc(var(--topbar-h, 114px) + 48px) var(--container-pad) 64px;
  }

  .products-scroll .product-card {
    width: min(575px, 84vw);
  }

  .work-grid {
    grid-template-columns: 1fr;
    gap: 32px;
    width: calc(100% - 2 * var(--container-pad));
  }
}

@media (max-width: 640px) {
  .products-topbar {
    flex-wrap: wrap;
  }

  /* The topbar's "Get in Touch" pill collapses to an icon-only badge
     on phones — the SVG already carries its own background circle and
     glow (baked into the asset), so the pill itself is stripped down
     to a plain wrapper rather than keeping its own box/shadow/fixed
     width behind it. Scoped to .products-topbar so the wider "All
     Products"/FAQ CTA pills elsewhere on a page are unaffected. */
  .products-topbar .product-nav-pill {
    width: auto;
    height: auto;
    padding: 0;
    background: transparent;
    box-shadow: none;
  }

  .products-topbar .product-nav-pill:hover {
    box-shadow: none;
  }

  .products-topbar .product-nav-pill-label,
  .products-topbar .product-nav-indicator {
    display: none;
  }

  .products-topbar .product-nav-pill-icon {
    display: block;
    width: 41px;
    height: 41px;
  }
}

/* ==========================================================================
   Product detail page (product-swaraj.html, Figma node 231:19265) —
   shares .products-topbar/.product-nav-pill/.product-card with the
   Products listing page (products.html); js/products.js's topbar
   scroll-transform logic is reused as-is (it's guarded per-feature, so
   it simply no-ops for the .products-scroll/.products-hero/.products-list
   selectors this page doesn't have).
   ========================================================================== */
.product-detail-hero {
  position: relative;
  padding: calc(var(--topbar-h, 114px) + 64px) var(--container-pad) 80px;
  background: #0d1117;
  overflow: clip;
}

/* Same ambient glow language as .products-hero. */
.product-detail-hero::before {
  content: "";
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 700px;
  background: radial-gradient(ellipse 60% 60% at 50% 0%, rgba(0, 16, 119, 0.55), transparent 70%);
  pointer-events: none;
}

.product-detail-back {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 56px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.6vw, 1.5rem);
  color: #bdbdbd;
  text-decoration: none;
}

.product-detail-back:hover {
  color: var(--text);
}

.product-detail-back-dots {
  display: inline-flex;
  gap: 5px;
}

.product-detail-back-dots span {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.55);
}

.product-detail-back-dots span:last-child {
  background: rgba(255, 255, 255, 0.9);
}

.product-detail-hero-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 48px;
  flex-wrap: wrap;
}

.product-detail-intro {
  flex: 1 1 238px;
  min-width: 0;
}

.product-detail-title {
  margin: 0 0 40px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(2rem, 4.2vw, 3.75rem);
  line-height: 1.15;
  color: #fff;
  text-transform: capitalize;
  max-width: 735px;
}

.product-detail-tags {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
}

.product-detail-tag {
  padding: 12px 20px;
  border: 1px solid #353743;
  border-radius: 8px;
  background: linear-gradient(360deg, rgb(3 12 60 / 57%) 27.83%, rgb(51 51 51 / 20%) 108.125%);
  font-family: var(--font-body);
  font-size: clamp(0.9rem, 1.2vw, 1.25rem);
  color: #e0e0e0;
  white-space: nowrap;
}

/* Same rim-glow card as the product listing, just a different fill/
   radius for this "at a glance" summary variant (Industry + CTA only
   — the name/tags are already shown in the hero title above). */
.product-detail-card {
  background: rgba(0, 39, 92, 0.22);
  border-radius: 36px;
  width: 575px;
  max-width: 100%;
  flex-shrink: 0;
}

.product-detail-about {
  padding: 80px var(--container-pad) 120px;
  background: #0d1117;
}

.product-detail-about-title {
  display: flex;
  align-items: flex-end;
  gap: 16px;
  margin: 0 0 20px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.25;
  color: #fff;
}

.product-detail-about-arrow {
  flex-shrink: 0;
  width: 35px;
  height: 35px;
}

.product-detail-about-text {
  margin: 0;
  max-width: 100%;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.4vw, 1.5rem);
  line-height: 1.5;
  color: #c3c3c3;
}

/* User Story / Dashboard UX (Figma node 308:5201) — two stacked
   heading+paragraph blocks, same visual language as "About Swaraj"
   above it, so this reuses that pattern's exact values under its own
   class names rather than the "about"-prefixed ones. */
.product-story {
  padding: 40px var(--container-pad) 60px;
  background: #0d1117;
  display: flex;
  flex-direction: column;
  gap: 60px;
}

.product-story-block {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.product-story-title {
  display: flex;
  align-items: flex-end;
  gap: 16px;
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.25;
  color: #fff;
}

.product-story-title--single {
  align-items: center;
}

.product-story-arrow {
  flex-shrink: 0;
  width: 35px;
  height: 35px;
}

.product-story-text {
  margin: 0;
  max-width: 100%;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.4vw, 1.5rem);
  line-height: 1.5;
  color: #c3c3c3;
}

/* Approach (Book Better, Figma node 323:9804) — a second
   .product-story-block reusing that block's own heading pattern
   (.product-story-title--single), just with a row of step-circles
   connected by dashed lines instead of a paragraph. */
.product-approach-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.product-approach-step {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(110px, 10.6vw, 204px);
  aspect-ratio: 1;
  padding: 12px;
  border-radius: 50%;
  background: rgba(0, 16, 119, 0.22);
  text-align: center;
  color: #fff;
  font-family: var(--font-body);
  font-size: clamp(0.85rem, 1.25vw, 1.5rem);
  line-height: 1.3;
}

.product-approach-connector {
  flex: 1 1 0;
  min-width: 16px;
  height: 0;
  border-top: 2px dashed #a1a1a1;
}

@media (max-width: 900px) {
  .product-approach-row {
    flex-direction: column;
    gap: 16px;
  }

  .product-approach-step {
    width: clamp(140px, 42vw, 180px);
  }

  .product-approach-connector {
    flex: 0 0 auto;
    min-width: 0;
    width: 0;
    height: 24px;
    border-top: none;
    border-left: 2px dashed #a1a1a1;
  }
}

@media (max-width: 900px) {
  .product-detail-hero {
    padding: calc(var(--topbar-h, 114px) + 48px) var(--container-pad) 64px;
  }

  .product-detail-hero-row {
    flex-direction: column;
    align-items: flex-start;
  }

  .product-detail-card {
    width: 100%;
  }
}

/* Generic scroll-reveal utility (used by .product-problems below, and
   reusable for any future section that should fade/slide up into view
   rather than being visible immediately on load) — js/products.js
   adds .is-revealed via a one-shot IntersectionObserver once the
   element scrolls into the viewport. */
.scroll-reveal {
  opacity: 0;
  transform: translateY(60px);
  transition: opacity 0.8s ease, transform 0.8s ease;
}

.scroll-reveal.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* User Problem grid (Figma node 280:5490) — 5 items in a staggered
   two-row "checkerboard": odd items (01/03/05) sit in row 1, even
   items (02/04) sit in row 2 offset half a column right, with
   vertical dividers between all 5 columns and one horizontal divider
   roughly between the two rows. */
.product-problems {
  padding: 40px var(--container-pad) 120px;
  background: #0d1117;
}

.product-problems-title {
  display: flex;
  align-items: flex-end;
  gap: 16px;
  margin: 0 0 40px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.25;
  color: #fff;
}

.product-problems-arrow {
  flex-shrink: 0;
  width: 35px;
  height: 35px;
}

.product-problems-grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: auto auto;
}

.product-problems-divider {
  position: absolute;
  background: rgba(255, 255, 255, 0.12);
}

/* Dividers "draw" from one end to the other on reveal — scaleY/scaleX
   from 0 with transform-origin pinned to the starting edge, rather
   than a plain fade, so they read as a line being drawn. Gated on the
   section's own .is-revealed (added once, one-shot, by the generic
   .scroll-reveal IntersectionObserver in js/products.js — same
   trigger the section-level fade already uses), so no extra JS is
   needed here. */
.product-problems-divider--v {
  top: 0;
  bottom: 0;
  width: 3px;
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.5s ease;
}

.product-problems-divider--v:nth-of-type(1) { left: 20%; transition-delay: 0.35s; }
.product-problems-divider--v:nth-of-type(2) { left: 40%; transition-delay: 0.45s; }
.product-problems-divider--v:nth-of-type(3) { left: 60%; transition-delay: 0.55s; }
.product-problems-divider--v:nth-of-type(4) { left: 80%; transition-delay: 0.65s; }

.product-problems-divider--h {
  left: 0;
  right: 0;
  top: 50%;
  height: 3px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.6s ease 0.75s;
}

.product-problems.is-revealed .product-problems-divider--v,
.product-problems.is-revealed .product-problems-divider--h {
  transform: none;
}

.product-problem {
  padding: 40px 24px;
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.product-problems.is-revealed .product-problem {
  opacity: 1;
  transform: translateY(0);
}

/* nth-of-type (not nth-child) so this stays correct regardless of how
   many .product-problems-divider <span> siblings precede these <div>s
   in the markup — it counts only among same-tag siblings. Also carries
   each item's reveal delay, staggered in reading order (01→05) so the
   number + title fade/slide in one card at a time after the dividers
   have drawn in. */
.product-problem:nth-of-type(1) { grid-column: 1; grid-row: 1; transition-delay: 0.85s; }
.product-problem:nth-of-type(2) { grid-column: 2; grid-row: 2; transition-delay: 0.95s; }
.product-problem:nth-of-type(3) { grid-column: 3; grid-row: 1; transition-delay: 1.05s; }
.product-problem:nth-of-type(4) { grid-column: 4; grid-row: 2; transition-delay: 1.15s; }
.product-problem:nth-of-type(5) { grid-column: 5; grid-row: 1; transition-delay: 1.25s; }

.product-problem-num {
  display: block;
  margin-bottom: 10px;
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 1.6vw, 1.75rem);
  color: #e3e3e3;
}

.product-problem-title {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.1rem, 1.6vw, 2rem);
  line-height: 1.3;
  color: #fff;
}

@media (max-width: 900px) {
  .product-problems-grid {
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: none;
    border-top: none;
  }

  .product-problems-divider {
    display: none;
  }

  .product-problem {
    padding: 24px;
    border: 1px solid rgba(255, 255, 255, 0.12);
  }

  /* Same specificity as the base :nth-of-type placement rules above
     (a plain .product-problem class here wouldn't win against them —
     :nth-of-type outweighs source order) so this actually resets it
     back to normal grid flow instead of silently losing to them. */
  .product-problem:nth-of-type(1),
  .product-problem:nth-of-type(2),
  .product-problem:nth-of-type(3),
  .product-problem:nth-of-type(4),
  .product-problem:nth-of-type(5) {
    grid-column: auto;
    grid-row: auto;
  }
}

@media (max-width: 640px) {
  .product-problems-grid {
    grid-template-columns: 1fr;
  }
}

/* Book Better's User Problem grid (Figma node 323:11499) — a plain
   2x2 (4 items) rather than Swaraj's 5-item staircase above, so it
   only needs one vertical + one horizontal divider, both centered.
   .product-problems-divider--v:nth-of-type(1) otherwise defaults to
   left:20% (the first of Swaraj's 4 dividers) — overridden here since
   this page's markup only has the one. */
.product-problems-grid--2x2 {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto auto;
}

.product-problems-grid--2x2 .product-problems-divider--v:nth-of-type(1) {
  left: 50%;
}

.product-problems-grid--2x2 .product-problem:nth-of-type(1) { grid-column: 1; grid-row: 1; }
.product-problems-grid--2x2 .product-problem:nth-of-type(2) { grid-column: 1; grid-row: 2; }
.product-problems-grid--2x2 .product-problem:nth-of-type(3) { grid-column: 2; grid-row: 1; }
.product-problems-grid--2x2 .product-problem:nth-of-type(4) { grid-column: 2; grid-row: 2; }

/* Matching specificity to the 4 placement rules just above, and
   declared after them here — for equal specificity, source order
   decides, so without living below them this reset would lose and
   the 2x2 placement would wrongly persist past this breakpoint
   instead of collapsing like every other .product-problems-grid. */
@media (max-width: 900px) {
  .product-problems-grid--2x2 .product-problem:nth-of-type(1),
  .product-problems-grid--2x2 .product-problem:nth-of-type(2),
  .product-problems-grid--2x2 .product-problem:nth-of-type(3),
  .product-problems-grid--2x2 .product-problem:nth-of-type(4) {
    grid-column: auto;
    grid-row: auto;
  }
}

/* Solution We Found (Figma nodes 280:7147 / 277:5100 / 277:5189) — a
   checklist beside a circular illustration; script.js's showSolution()
   auto-cycles both the highlighted list item and the matching
   illustration together on a timer (respects prefers-reduced-motion,
   same pattern as the Products/Clients carousels elsewhere). */
.product-solutions {
  padding: 40px var(--container-pad) 120px;
  background: #0d1117;
}

.product-solutions-title {
  display: flex;
  align-items: flex-end;
  gap: 16px;
  margin: 0 0 40px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.25;
  color: #fff;
}

.product-solutions-arrow {
  flex-shrink: 0;
  width: 35px;
  height: 35px;
}

.product-solutions-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}

.product-solutions-list {
  flex: 1 1 480px;
  max-width: 795px;
  margin: 0;
  padding: 28px;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 18px;
  border: 2px solid rgba(161, 161, 161, 0.31);
  border-radius: 32px;
}

.product-solution {
  display: flex;
  align-items: center;
  gap: 36px;
}

.product-solution-check {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 35px;
  height: 35px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
}

.product-solution-check img {
  width: 16px;
  height: auto;
}

.product-solution-text {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1rem, 1.6vw, 1.75rem);
  color: #737373;
  transition: color 0.4s ease;
}

.product-solution.is-active .product-solution-text {
  font-weight: 500;
  color: #fff;
}

.product-solutions-illustration {
  position: relative;
  flex-shrink: 0;
  width: clamp(280px, 34vw, 650px);
  aspect-ratio: 1;
}

.product-solutions-inner {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 56.8%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: clamp(8px, 1.8vw, 16px) solid #0d1117;
  background: rgba(255, 255, 255, 0.02);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.product-solutions-icon-stack {
  position: relative;
  display: grid;
  width: 50%;
  aspect-ratio: 1;
}

.product-solutions-icon {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 0.6s ease;
}

.product-solutions-icon.is-active {
  opacity: 1;
}

@media (max-width: 900px) {
  .product-solutions-row {
    flex-direction: column;
  }

  /* flex:1 1 480px on .product-solutions-list sets its *main-axis*
     size — width while .product-solutions-row is a row (desktop), but
     once it switches to flex-direction:column here the main axis is
     vertical, so that same rule was forcing a 480px-tall card instead
     (plus flex-grow:1 stretching it further into any extra column
     space) regardless of how little content it actually held. Same
     bug class as .faq-list/.process-right earlier — reset the basis
     back to auto so height comes from content again. */
  .product-solutions-list {
    flex-basis: auto;
    max-width: 100%;
  }

  .product-solutions-illustration {
    order: -1;
    width: clamp(240px, 60vw, 400px);
  }
}

/* Impact (Figma node 280:10361) — a 3-column stat bar (10+ Onboarded
   Landlords / 4.9/5 User Rating / 100% Customer Support), same
   number+label idea as the homepage's Trusted By Clients stats but a
   distinct bordered/divided grid layout, so it gets its own classes
   rather than reusing .stat/.stat-figure directly. */
.product-impact {
  padding: 40px var(--container-pad) 60px;
  background: #0d1117;
}

.product-impact-title {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 40px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  color: #fff;
}

.product-impact-arrow {
  width: 35px;
  height: 35px;
}

/* Same "draw in" treatment as .product-problems: the top/bottom rules
   and the between-column dividers are pseudo-elements (not borders)
   so they can scale in from one end, gated on the section's own
   .is-revealed (added once, one-shot, by the generic .scroll-reveal
   IntersectionObserver in js/products.js). Then each stat's own
   number + label fade/slide in after, staggered left to right. */
.product-impact-stats {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.product-impact-stats::before,
.product-impact-stats::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: rgba(255, 255, 255, 0.12);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s ease;
}

.product-impact-stats::before { top: 0; }
.product-impact-stats::after { bottom: 0; }

.product-impact.is-revealed .product-impact-stats::before,
.product-impact.is-revealed .product-impact-stats::after {
  transform: scaleX(1);
}

.product-impact-stat {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 48px 24px;
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.product-impact.is-revealed .product-impact-stat {
  opacity: 1;
  transform: translateY(0);
}

.product-impact-stat:nth-child(1) { transition-delay: 0.55s; }
.product-impact-stat:nth-child(2) { transition-delay: 0.65s; }
.product-impact-stat:nth-child(3) { transition-delay: 0.75s; }

.product-impact-stat:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 1px;
  background: rgba(255, 255, 255, 0.12);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.4s ease;
}

.product-impact-stat:nth-child(1)::after { transition-delay: 0.35s; }
.product-impact-stat:nth-child(2)::after { transition-delay: 0.45s; }

.product-impact.is-revealed .product-impact-stat:not(:last-child)::after {
  transform: scaleY(1);
}

.product-impact-number {
  display: flex;
  align-items: flex-end;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(2.5rem, 5.5vw, 5rem);
  line-height: 1;
  color: #fff;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.product-impact-suffix {
  font-size: 0.5em;
}

.product-impact-suffix--pct {
  font-size: 0.6em;
}

.product-impact-label {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.6vw, 1.875rem);
  line-height: 1.25;
  color: #bebebe;
}

/* Other Products (Figma node 280:10496 badge + the same free-scrolling
   .products-scroll row from products.html, arrow buttons included —
   already wired up by products.js, no extra JS needed). */
.product-other {
  padding: 0 0 120px;
  background: #0d1117;
}

.product-other-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 var(--container-pad) 40px;
  padding: 16px 20px;
  border-radius: 16px;
  background: #04070b;
  box-shadow: 0 5px 14px rgba(146, 146, 146, 0.25);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: clamp(1rem, 1.6vw, 1.5rem);
  color: #f4f1ea;
}

.product-other-dots {
  display: inline-flex;
  gap: 5px;
}

.product-other-dots span {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
}

/* Simplify page combines Other Work with a "Custom Software
   Development" CTA in the same row, unlike Swaraj's Other Products
   (its own full-width .products-scroll row) — .product-other-row is
   an opt-in wrapper, so Swaraj's plain badge+scroll markup is
   untouched. The badge's own left/right margin is reset to 0 here
   since this row already supplies the section's side padding. */
.product-other-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 48px;
  padding: 0 var(--container-pad);
}

.product-other-row .product-other-badge {
  margin-left: 0;
  margin-right: 0;
}

.product-other-list {
  flex: 0 1 575px;
  min-width: 0;
}

.product-other-cta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 32px;
  flex: 1 1 360px;
}

.product-other-cta-line {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: clamp(1.5rem, 2.4vw, 2.5rem);
  color: #f4f1ea;
}

.product-other-cta-line--strong {
  font-weight: 600;
}

@media (max-width: 900px) {
  .product-impact-stats {
    grid-template-columns: 1fr;
  }

  /* Single column now, so the between-item divider runs along the
     bottom edge (horizontal draw) instead of the right edge
     (vertical draw) — same pseudo-element, re-oriented. */
  .product-impact-stat:not(:last-child)::after {
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    height: 1px;
    transform: scaleX(0);
    transform-origin: left;
  }

  .product-impact.is-revealed .product-impact-stat:not(:last-child)::after {
    transform: scaleX(1);
  }
}

/* =============================================================
   About page (about.html)
   ============================================================= */

/* Repeats the homepage's own hero statement (Figma nodes 213:13594/
   213:13595 — same copy as .hero-title/.hero-subtitle) as its own
   centered block, sitting right above the sticky "Build With Us"
   divider below it. New classes rather than reusing .hero-title/
   .hero-subtitle directly, since those are wired to the homepage's
   own typewriter/scroll-reveal script (.hero.is-title-revealed etc.)
   which this page doesn't load — entrance animation here comes from
   the generic .scroll-reveal class instead. */
.about-statement {
  position: relative;
  overflow: clip;
  padding: 100px var(--container-pad) 80px;
  background: #0d1117;
  text-align: center;
}

/* Same ambient glow as .products-list::before — see that comment. */
.about-statement::before {
  content: "";
  position: absolute;
  inset: -10% -10% auto -10%;
  height: 700px;
  background: radial-gradient(ellipse 60% 60% at 50% 0%, rgba(0, 16, 119, 0.55), transparent 70%);
  pointer-events: none;
}

/* No max-width cap here — the section's own --container-pad side
   padding already constrains the available width, and the two lines
   forced by the <br> in the markup need to each fit on their own
   single line at desktop sizes rather than wrapping a second time
   (a tighter cap was cutting "Engineering digital products" onto two
   lines by itself, turning the intended 2 lines into 4). */
.about-statement-title {
  margin: 0 0 24px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(2.1rem, 5.4vw, 5rem);
  line-height: 1.12;
  color: #f4f1ea;
}

.about-statement-text {
  margin: 0 auto;
  max-width: 62ch;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.6vw, 1.625rem);
  line-height: 1.5;
  color: #989aa4;
}

/* Recurring section-break band (Figma "Line 27"/"Line 28") — two
   gradient-faded diagonal lines flanking a centered CTA, repeated
   before Our Story/Our Process/FAQ. Same ambient glow language as
   .products-hero::before, tall enough to bleed into the section
   directly below since there's no gap between them. */
.about-divider {
  position: relative;
  display: flex;
  flex-direction: row-reverse;
  gap: 24px;
  padding: 48px var(--container-pad) 100px;
  background: #0d1117;
  overflow: clip;
}

.about-divider::before {
  content: "";
  position: absolute;
  inset: -10% -10% auto -10%;
  height: 500px;
  background: radial-gradient(ellipse 0% 60% at 50% 0%, rgba(0, 16, 119, 0.5), transparent 70%);
  pointer-events: none;
}

.about-divider-line {
  position: relative;
  flex: 1 1 auto;
  height: 30px;
  min-width: 0;
}

.about-divider-line--right { transform: scaleX(-1); }

/* First divider only (right after the Hero) — scrolls normally until
   it reaches the top (just below the fixed topbar), then sticks there
   while Our Story AND Our Process both keep scrolling underneath it.
   .about-story-wrap is this divider's positioned ancestor, now
   spanning both of those sections, so the stickiness releases only
   once the LAST one (Our Process) finishes scrolling past — not
   pinned for the rest of the page. Our Process's own sticky elements
   (.process-intro, .about-process-card) read --about-divider-h so
   they sit below this divider's bottom edge instead of underneath it. */
.about-story-wrap {
  position: relative;
}

.about-divider--sticky {
  position: sticky;
  top: var(--topbar-h, 114px);
  z-index: 20;
  padding-bottom: 80px;

  overflow: visible;
}

/* Fade mask: a scrim that stays pinned right under the sticky bar
   (it's positioned relative to the sticky element itself, so it moves
   with it) — Our Story's content scrolls up through this zone and
   visually fades out as it passes under the bar. */
.about-divider--sticky::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 140px;
  background: linear-gradient(to bottom, #0d1117 0%, rgba(13, 17, 23, 0) 100%);
  pointer-events: none;
  z-index: 1;
}

.about-divider-cta {
  position: relative;
  flex-shrink: 0;
  font-size: 20px;
  padding: 12px 22px;
  box-shadow: 0 -1px 12.8px #da7c41;
}

.about-divider-title {
  position: relative;
  flex-shrink: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  color: #fff;
}

/* Bold caps label + full-width gradient underline (Figma nodes
   217:13625/217:13626) — a simpler, dot-less variant of the
   homepage's .section-eyebrow, used only on this page. */
.about-eyebrow {
  display: flex;
  flex-direction: column;
  gap: 23px;
  margin-bottom: 24px;
}

.about-eyebrow-label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.1rem, 1.4vw, 1.25rem);
  color: #fff;
}

.about-eyebrow-line {
  height: 1px;
  width: 100%;
  max-width: 537px;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.5), transparent);
}

.about-story {
  padding: 80px var(--container-pad) 100px;
  background: #0d1117;
}

.about-story-row {
  display: flex;
  align-items: center;
  gap: 80px;
}

.about-story-content {
  flex: 1 1 480px;
  min-width: 0;
}

.about-story-text {
  margin: 0 0 32px;
  max-width: 46ch;
  font-family: var(--font-body);
  font-size: clamp(1.1rem, 1.5vw, 1.5rem);
  line-height: 1.5;
  color: #bdbdbd;
}

.about-story-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.about-story-image {
  flex: 0 0 auto;
  width: clamp(260px, 30vw, 448px);
  aspect-ratio: 448 / 452;
  padding: 15px;
  border: 1px solid #485ac9;
  border-radius: 23px;
  background: rgba(13, 23, 82, 0.16);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

.about-story-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 20px;
}

/* Our Process — a native CSS scroll-stack. The left column
   (.process-intro/.process-intro-title, shared with the homepage's
   #panelProcess) becomes sticky on THIS page only, scoped through the
   .about-process ancestor so the homepage — where .process-intro sits
   in a completely different, non-sticky layout — is untouched. The
   right column's 5 step cards are ALSO each position:sticky, at the
   SAME top offset: as the user scrolls, each card arrives, pins in
   place, and is then visually covered by the next one sliding up over
   it — the covering happens for free from DOM order (later siblings
   paint on top) plus matching z-index per card as a safety net. No
   scroll-hijacking, no wheel/touch capture — this is why "scroll
   anywhere" now just falls out of using real position:sticky instead
   of the previous absolutely-positioned 2-card version. A passive
   scroll listener in js/products.js (updateAboutProcessStack) only
   toggles which card counts as .is-active (full size, bright, orange
   icon) vs .is-passed (scaled down, dimmed, sitting underneath) —
   see there for the full logic. */
.about-process {
  padding: 60px var(--container-pad) 100px;
  background: #0d1117;
}

/* The "Build With Us" divider above this section stays pinned (see
   .about-divider--sticky) all the way through Our Process too now, so
   both sticky elements here need to clear ITS bottom edge — not just
   the topbar's — or it would sit on top of them (it has the higher
   z-index). --about-divider-h is measured in js/products.js. */
.about-process .process-intro {
  position: sticky;
  top: calc(var(--topbar-h, 114px) + var(--about-divider-h, 130px) + 24px);
  height: fit-content;
}

.about-process-stage {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 760px;
}

.about-process-card {
  position: sticky;
  top: calc(var(--topbar-h, 114px) + var(--about-divider-h, 130px) + 24px);
  margin-bottom: 32px;
  transition: transform 0.35s ease, opacity 0.35s ease;
}

/* Every card's "dwell time" while stuck comes from the NEXT card's
   own height — that's how much the page has to scroll before the
   next one catches up and covers it. The last card has no next
   sibling to borrow that runway from, so without its own trailing
   space here it becomes active for barely an instant before the
   section's content just ends and native scroll carries straight on
   into FAQ. Matching a full card's height (as this originally did)
   overcorrected — that read as the 5th card taking much more
   scrolling than 1-4 to settle, since the extra room sits right where
   the user is still scrolling toward/through it. A smaller runway is
   enough to fix the premature hand-off without that. */
.about-process-card:last-child {
  margin-bottom: clamp(90px, 9vw, 130px);
}

/* Matches DOM/scroll order so a later card is guaranteed to paint
   over an earlier one even if stacking-context quirks would otherwise
   leave that to chance. */
.about-process-card:nth-of-type(1) { z-index: 1; }
.about-process-card:nth-of-type(2) { z-index: 2; }
.about-process-card:nth-of-type(3) { z-index: 3; }
.about-process-card:nth-of-type(4) { z-index: 4; }
.about-process-card:nth-of-type(5) { z-index: 5; }

.about-process-card-outer {
  background: #2b2b2b;
  border: 1px solid #6b6b6b;
  padding: 8px;
  border-radius: 32px;
}

/* min-height (not height) reproduces Figma's 755x321 card ratio at
   the reference width while still letting a card grow taller if its
   own description needs more room, rather than risking clipped text. */
.about-process-card-inner {
  min-height: clamp(248px, 22vw, 303px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 20px;
  background: #04070b;
  border: 1px solid #04070b;
  border-radius: 24px;
  padding: clamp(28px, 4vw, 48px) clamp(24px, 3.5vw, 36px);
}

/* Icon + step name, grouped together (Figma node 606:8861) so the
   20px gap above only applies once, between this group and the
   description paragraph — not separately between icon/title too. */
.about-process-card-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 24px;
  width: 100%;
}

.about-process-card-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  flex-shrink: 0;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: #1a1a1a;
}

/* Two real icon files stacked and crossfaded (same gray art already
   used on the homepage's Our Process, plus a real Figma-exported
   orange-tinted copy for the active state — see
   assets/img/process/icon-*-active.svg) rather than a CSS-masked
   glyph, for reliable cross-browser rendering. */
.about-process-card-icon-img {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 48px;
  height: 48px;
  transition: opacity 0.35s ease;
}

.about-process-card-icon-img--active {
  opacity: 0;
}

.about-process-card-title {
  margin: 0;
  font-family: "Inter", sans-serif;
  font-weight: 600;
  font-size: clamp(1.15rem, 1.9vw, 1.625rem);
  color: #9d9d9d;
  transition: color 0.35s ease;
}

.about-process-card-text {
  margin: 0;
  max-width: 46ch;
  color: #9d9d9d;
  font-family: "Inter", sans-serif;
  font-size: clamp(1rem, 1.6vw, 1.5rem);
  line-height: 1.4;
  transition: color 0.35s ease;
}

/* Active = the topmost card currently pinned and not yet covered by
   the next one arriving. */
.about-process-card.is-active .about-process-card-icon-img { opacity: 0; }
.about-process-card.is-active .about-process-card-icon-img--active { opacity: 1; }
.about-process-card.is-active .about-process-card-title { color: #fff; }
.about-process-card.is-active .about-process-card-text { color: #fff; }

/* Passed = an earlier card the next one has now covered — shrinks and
   dims as it recedes, matching the brief's "scales down, dims, and
   rests at the top edge" description. */
@media (prefers-reduced-motion: no-preference) {
  .about-process-card.is-passed {
    transform: scale(0.95);
    opacity: 0.6;
  }
}

@media (max-width: 900px) {
  .about-process {
    padding: 48px var(--container-pad) 72px;
  }

  /* .process-layout flips to a column below — a sticky intro sitting
     ABOVE a column of also-sticky cards would fight them for the same
     pinned real estate, so the sticky treatment is desktop-only;
     .about-process .process-intro needs to be repeated here (not just
     left to the shared .process-intro{position:static} reset a few
     rules below) since it's more specific and would otherwise win. */
  .about-process .process-intro {
    position: static;
    height: auto;
  }

  .about-process-stage {
    width: 100%;
    max-width: 100%;
  }

  .about-process-card {
    top: calc(var(--topbar-h, 114px) + var(--about-divider-h, 100px) + 16px);
    margin-bottom: 24px;
  }

  .about-process-card:last-child {
    margin-bottom: clamp(80px, 14vw, 120px);
  }

  .about-process-card-inner {
    min-height: clamp(236px, 36vw, 276px);
    padding: 28px 24px;
    gap: 18px;
  }

  .about-process-card-head {
    gap: 20px;
  }
}

@media (max-width: 480px) {
  .about-process-card:last-child {
    margin-bottom: clamp(70px, 26vw, 110px);
  }

  .about-process-card-inner {
    min-height: clamp(256px, 66vw, 296px);
    padding: 24px 20px;
  }

  .about-process-card-icon {
    width: 64px;
    height: 64px;
  }

  .about-process-card-icon-img {
    width: 42px;
    height: 42px;
  }
}

.about-faq {
  padding: 60px var(--container-pad) 100px;
  background: #0d1117;
}

@media (max-width: 900px) {
  .about-statement {
    padding: 64px var(--container-pad) 56px;
  }

  .about-divider {
    justify-content: center;
    padding: 40px var(--container-pad) 0;
  }

  .about-divider-line {
    display: none;
  }

  .about-divider--sticky {
    padding-bottom: 56px;
  }

  .about-divider--sticky::after {
    height: 90px;
  }

  .about-story {
    padding: 56px var(--container-pad) 72px;
  }

  .about-story-row {
    flex-direction: column;
  }

  /* Same flex-basis-becomes-wrong-axis bug fixed elsewhere this
     session (.faq-list, .process-right, .product-solutions-list):
     flex:1 1 480px sets *width* while .about-story-row is a row
     (desktop) — once it flips to flex-direction:column just above,
     that same 480px becomes a *height* instead, leaving unwanted
     empty space below shorter content. */
  .about-story-content {
    flex-basis: auto;
  }

  .about-story-image {
    width: 100%;
    max-width: 448px;
  }

  .about-faq {
    padding: 48px var(--container-pad) 72px;
  }
}

@media (max-width: 480px) {
  .about-statement {
    padding: 48px var(--container-pad) 40px;
  }

  /* The <br> in the markup forces a hard break between "Engineering
     digital products" and "with precision and purpose." — fine at
     desktop sizes where .about-statement-title's clamp() floor (2.1rem)
     still fits the longer line on one row, but at phone widths that
     floor is wider than the available column, forcing an unwanted
     second wrap inside the first line (2 lines becomes 3-4, the exact
     bug already fixed once for desktop). Drop the floor further here
     rather than relying on clamp()'s viewport-relative term alone. */
  .about-statement-title {
    font-size: clamp(1.65rem, 8vw, 2.1rem);
  }

  .about-divider-cta {
    font-size: 16px;
    padding: 10px 18px;
  }
}

/* ==========================================================================
   Careers page (careers.html, Figma node 231:9072) — shares
   .products-topbar/.products-hero/.site-footer with the other interior
   pages; the apply form + "Contact HR" card below are new to this page.
   ========================================================================== */
.careers-apply {
  position: relative;
  overflow: clip;
  padding: 64px var(--container-pad) 100px;
  background: #0d1117;
}

/* Same ambient glow as .products-list::before — see that comment. */
.careers-apply::before {
  content: "";
  position: absolute;
  inset: -10% -10% auto -10%;
  height: 700px;
  background: radial-gradient(ellipse 60% 60% at 50% 0%, rgba(0, 16, 119, 0.55), transparent 70%);
  pointer-events: none;
}

.careers-apply-row {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: clamp(40px, 6vw, 108px);
}

.careers-form {
  display: flex;
  flex-direction: column;
  /* gap: clamp(28px, 3.6vw, 52px); */
  gap: clamp(20px, 2.6vw, 40px);
  width: 100%;
  max-width: 780px;
  padding: 20px;
  border: 1px solid var(--border-soft);
  border-radius: 12px;
}

.careers-form-row {
  display: flex;
  gap: clamp(24px, 5.6vw, 108px);
}

.careers-field {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.careers-label {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: clamp(0.95rem, 1.2vw, 1.125rem);
  color: #fff;
}

.careers-input,
.careers-select {
  width: 100%;
  height: 45px;
  border: 1px solid var(--text-muted);
  border-radius: 8px;
  background: rgba(0, 16, 119, 0.07);
  color: #fff;
  font-family: var(--font-body);
  font-size: clamp(0.9rem, 1.1vw, 1rem);
}

.careers-input {
  padding: 10px 16px;
}

.careers-input::placeholder {
  color: #888;
}

.careers-input:focus,
.careers-select:focus {
  outline: none;
  border-color: var(--accent);
}

/* The real <input type="file"> is visually hidden — its <label> (the
   only thing sighted users interact with) reproduces the Figma upload
   button, and stays natively keyboard/screen-reader operable since a
   <label for="..."> forwards activation to the input either way. */
.careers-upload-input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.careers-upload {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  height: 45px;
  padding: 10px 16px;
  border-radius: 8px;
  background: #222;
  box-shadow: 0 0 4px rgba(255, 255, 255, 0.7);
  color: #fff;
  font-family: var(--font-body);
  font-size: clamp(0.9rem, 1.1vw, 1rem);
  cursor: pointer;
}

.careers-upload-input:focus-visible + .careers-upload {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.careers-upload-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.careers-upload-icon {
  flex-shrink: 0;
  display: flex;
}

/* Source SVG is a left-pointing arrow (Figma reuses one arrow glyph
   rotated per context) — rotated here to point up, matching "upload". */
.careers-upload-icon img {
  width: 22px;
  height: auto;
  transform: rotate(90deg);
}

.careers-select-wrap {
  position: relative;
}

/* .careers-select is now the custom toggle button (see .careers-select-menu
   below) rather than the native <select> — a real <select>'s own open
   dropdown is OS-rendered and can't be given a border-radius or a capped,
   scrollable height, which is exactly what this list (9 roles + Other)
   needs. The real, submittable <select> still exists (.careers-select-native)
   but is visually hidden, kept in sync by js/products.js. */
.careers-select {
  display: flex;
  align-items: center;
  padding: 10px 40px 10px 16px;
  appearance: none;
  -webkit-appearance: none;
  text-align: left;
  color: #888;
  cursor: pointer;
}

.careers-select.has-value {
  color: #fff;
}

/* Mirrors .careers-upload-input's visually-hidden technique — kept
   focusable/clipped rather than display:none so it still participates
   in the form's native required-field validation. */
.careers-select-native {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.careers-select-icon {
  position: absolute;
  right: 16px;
  top: 50%;
  width: 16px;
  height: auto;
  transform: translateY(-50%);
  pointer-events: none;
}

/* Same bordered-panel recipe as .nav-dropdown-menu/.services-page-dropdown-menu,
   but capped to 4 rows tall (36px each) with the rest reachable by
   scrolling — this list is longer than either of those menus. */
.careers-select-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  z-index: 5;
  max-height: 172px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--bg-panel);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 8px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
}

.careers-select-menu.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.careers-select-menu button {
  flex-shrink: 0;
  height: 36px;
  padding: 0 10px;
  border: none;
  border-radius: 6px;
  background: none;
  color: #fff;
  font-family: var(--font-body);
  font-size: 0.9rem;
  text-align: left;
  cursor: pointer;
}

.careers-select-menu button:hover,
.careers-select-menu button.is-active {
  background: rgba(255, 255, 255, 0.06);
}

.careers-submit {
  padding: 16px 18px;
  border: none;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1rem, 1.3vw, 1.25rem);
  cursor: pointer;
  transition: background 0.2s ease;
}

.careers-submit:hover {
  background: var(--accent-hover);
}

/* Shared post-submit confirmation popup — used by both the Careers
   form and the Get in Touch form (see contact.html), since neither
   page has a real backend and both need the exact same "thanks, we
   got it" confirmation. Plain fixed overlay + centered card, toggled
   via the [hidden] attribute (see wireFormPopup in js/products.js)
   rather than opacity/visibility like the nav/services dropdowns,
   since this needs to block interaction with the rest of the page
   while it's up.
   display:flex lives on the :not([hidden]) variant, not the bare
   class — plain [hidden] and .form-popup are equal specificity, and
   an author rule wins that tie over the UA stylesheet's
   [hidden]{display:none}, so a flat "display:flex" here would show
   the popup at all times regardless of the hidden attribute. */
.form-popup {
  position: fixed;
  inset: 0;
  z-index: 50;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.form-popup:not([hidden]) {
  display: flex;
}

.form-popup-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
}

.form-popup-card {
  position: relative;
  width: 100%;
  max-width: 420px;
  padding: 40px 32px;
  border: 1px solid var(--border-soft);
  border-radius: 24px;
  background: var(--bg-panel);
  text-align: center;
}

.form-popup-close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}

.form-popup-title {
  margin: 0 0 12px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  color: #fff;
}

.form-popup-text {
  margin: 0 0 28px;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: clamp(0.9rem, 1.1vw, 1.05rem);
  line-height: 1.6;
}

.form-popup-ok {
  padding: 14px 32px;
  border: none;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  cursor: pointer;
  transition: background 0.2s ease;
}

.form-popup-ok:hover {
  background: var(--accent-hover);
}

.careers-hr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
  max-width: 408px;
}

.careers-hr-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 2vw, 2.125rem);
  color: #fff;
}

.careers-hr-cards {
  display: flex;
  flex-direction: column;
  gap: 41px;
  width: 100%;
}

.careers-hr-card {
  padding: 8px;
  border-radius: 12px;
  background: rgba(14, 17, 33, 0.2);
}

.careers-hr-card-inner {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  border: 1px solid #43486b;
  border-radius: 8px;
  background: rgba(0, 16, 119, 0.04);
}

.careers-hr-label {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1rem, 1.3vw, 1.25rem);
  color: #c8c8c8;
}

.careers-hr-value {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: clamp(0.95rem, 1.1vw, 1.125rem);
  line-height: 1.55;
  color: #fff;
}

.careers-hr-value a {
  color: inherit;
  text-decoration: none;
}

.careers-hr-value a:hover {
  color: var(--accent);
}

@media (max-width: 900px) {
  .careers-apply-row {
    flex-direction: column;
    align-items: stretch;
    gap: 56px;
  }

  .careers-form,
  .careers-hr {
    max-width: 100%;
  }

  .careers-hr {
    align-items: flex-start;
  }

  .careers-hr-cards {
    max-width: 408px;
  }
}

@media (max-width: 640px) {
  .careers-apply {
    padding: 48px var(--container-pad) 72px;
  }

  .careers-form-row {
    flex-direction: column;
    gap: 24px;
  }
}

/* ==========================================================================
   Get In Touch page (contact.html, Figma node 220:20466) — shares
   .products-topbar/.products-hero/.site-footer with the other interior
   pages, and reuses the same form-field/info-card anatomy as Careers'
   apply form + Contact HR card (.careers-form/.careers-hr-card — see
   that section), just under new page-scoped class names since this is
   a different page with one field fewer (no resume/role row) plus a
   full-width message textarea, and 4 info cards instead of 2.
   ========================================================================== */
.contact-apply {
  position: relative;
  overflow: clip;
  padding: 64px var(--container-pad) 100px;
  background: #0d1117;
}

/* Same ambient glow as .products-list::before/.careers-apply::before
   — see the comment on .products-list::before. */
.contact-apply::before {
  content: "";
  position: absolute;
  inset: -10% -10% auto -10%;
  height: 700px;
  background: radial-gradient(ellipse 60% 60% at 50% 0%, rgba(0, 16, 119, 0.55), transparent 70%);
  pointer-events: none;
}

.contact-heading {
  position: relative;
  margin: 0 0 48px;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 2.4vw, 2.25rem);
  color: #fff;
}

.contact-apply-row {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(24px, 3.6vw, 30px);
}

.contact-form {
  display: flex;
  flex-direction: column;
  /* gap: clamp(16px, 3.6vw, 24px); */
   gap: clamp(14px, 3.2vw, 20px);
  width: 100%;
  max-width: 811px;
  padding: 20px;
  border: 1px solid var(--border-soft);
  border-radius: 12px;
}

.contact-form-row {
  display: flex;
  gap: clamp(24px, 5.6vw, 108px);
}

.contact-field {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.contact-label {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: clamp(14px, 1.2vw, 16px);
  color: #fff;
}

.contact-input,
.contact-textarea {
  width: 100%;
  border: 1px solid var(--text-muted);
  border-radius: 8px;
  background: rgba(0, 16, 119, 0.07);
  color: #fff;
  font-family: var(--font-body);
  font-size: clamp(0.9rem, 1.1vw, 1rem);
  padding: 10px 16px;
}

.contact-input {
  height: 45px;
}

.contact-textarea {
  min-height: 150px;
  resize: vertical;
}

.contact-input::placeholder,
.contact-textarea::placeholder {
  color: #888;
}

.contact-input:focus,
.contact-textarea:focus {
  outline: none;
  border-color: var(--accent);
}

.contact-submit {
  padding: 16px 18px;
  border: none;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1rem, 1.3vw, 1.25rem);
  cursor: pointer;
  transition: background 0.2s ease;
}

.contact-submit:hover {
  background: var(--accent-hover);
}

.contact-info {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 100%;
  max-width: 408px;
}

.contact-info-card {
  padding: 8px;
  border-radius: 12px;
  background: rgba(14, 17, 33, 0.2);
}

.contact-info-card-inner {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  border: 1px solid #43486b;
  border-radius: 8px;
  background: rgba(0, 16, 119, 0.04);
}

.contact-info-label {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(14px, 1.3vw, 16px);
  color: #c8c8c8;
}

.contact-info-value {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: clamp(0.95rem, 1.1vw, 1.125rem);
  line-height: 1.55;
  color: #fff;
}

.contact-info-value a {
  color: inherit;
  text-decoration: none;
}

.contact-info-value a:hover {
  color: var(--accent);
}

@media (max-width: 900px) {
  .contact-apply-row {
    flex-direction: column;
    align-items: stretch;
    gap: 40px;
  }

  .contact-form,
  .contact-info {
    max-width: 100%;
  }
}

@media (max-width: 640px) {
  .contact-apply {
    padding: 48px var(--container-pad) 72px;
  }

  .contact-heading {
    margin-bottom: 32px;
  }

  .contact-form-row {
    flex-direction: column;
    gap: 24px;
  }
}

/* ==========================================================================
   Services page (services.html, Figma nodes 488:7027/642:7622/642:8043/
   645:8562) — a tab switcher between the 4 services (App/Web/Marketing/
   Design), each panel reusing the homepage's own .service-card-art
   markup/CSS verbatim (those selectors are unscoped, so they render
   identically here — see js/products.js for the tab-click logic).
   ========================================================================== */
.services-page {
  position: relative;
  overflow: clip;
  padding: 84px var(--container-pad) 100px;
  background: #0d1117;
}

/* Same ambient glow as .products-list::before/.careers-apply::before
   — see the comment on .products-list::before. */
.services-page::before {
  content: "";
  position: absolute;
  inset: -10% -10% auto -10%;
  height: 700px;
  background: radial-gradient(ellipse 60% 60% at 50% 0%, rgba(0, 16, 119, 0.55), transparent 70%);
  pointer-events: none;
}

.services-page-tabs {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  /* Pulled down by the card's own border width so the active tab's
     border/background lines up flush with it below — the "cut into
     the folder" look — rather than sitting above it with a gap. */
  margin-bottom: -2px;
}

/* Folder-tab look: square, borderless bottom edge (so it can merge
   into .services-page-card below it) and rounded top corners only.
   .services-page-tabs is position:relative (above), so it — and the
   active tab riding on it — paints over the card's own top border in
   the overlapping 2px, rather than the card's static-flow border
   showing through on top. */
.services-page-tab {
  border: 2px solid transparent;
  border-bottom: none;
  border-radius: 16px 16px 0 0;
  padding: 12px clamp(9px, 3vw, 12px) 14px;
  background: none;
  color: #fff;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.4vw, 1.375rem);
  cursor: pointer;
  transition: background 0.25s ease, border-color 0.25s ease;
}

/* Matches .services-page-card's own shell (border:#585858, bg:#222)
   exactly, so the seam between the active tab and the card disappears. */
.services-page-tab.is-active {
  border-color: #585858;
  background: #222;
}

/* Stand-in for the tab row above at ≤900px (see the media query below)
   — the floating-menu part reuses the same recipe as the homepage's
   Company dropdown (.nav-dropdown/.nav-dropdown-menu in the header),
   but the toggle itself is bordered (unlike Company's plain text +
   chevron) so it reads as a distinct field rather than a nav link.
   Reused here rather than 4 stacked tab buttons eating most of the
   screen before any actual content shows. See js/products.js for the
   open/close + selection wiring, which mirrors js/script.js's Company
   dropdown handling. */
.services-page-dropdown {
  display: none;
  position: relative;
  margin-bottom: 32px;
}

.services-page-dropdown-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 6px;
  padding: 12px 16px;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: none;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 18px;
  cursor: pointer;
}

.services-page-dropdown-menu {
  position: absolute;
  top: calc(100% + 14px);
  left: 0;
  right: 0;
  background: var(--bg-panel);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
  z-index: 5;
}

.services-page-dropdown-menu.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.services-page-dropdown-menu button {
  padding: 8px 10px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--text);
  text-align: left;
  font-family: var(--font-body);
  font-size: 15px;
  cursor: pointer;
}

.services-page-dropdown-menu button:hover,
.services-page-dropdown-menu button.is-active {
  background: rgba(255, 255, 255, 0.06);
}

.services-page-panels {
  position: relative;
}

.services-page-card {
  background: #222;
  border: 2px solid #585858;
  border-radius: clamp(24px, 4vw, 48px);
  padding: 16px;
}

/* App is the leftmost tab, Design the rightmost (see the folder-tab
   look on .services-page-tab above) — each one's card only ever shows
   while its own tab is active, so squaring off the corner the flush
   tab sits against doesn't need a separate active-state selector.
   Scoped to the same width the folder-tab look itself applies at:
   below 900px the tabs are replaced by the dropdown, so every card
   should keep its normal, fully-rounded corners there. */
@media (min-width: 901px) {
  .services-page-panel[data-panel="app"] .services-page-card {
    border-top-left-radius: 0;
  }

  .services-page-panel[data-panel="design"] .services-page-card {
    border-top-right-radius: 0;
  }
}

.services-page-card-inner {
  display: flex;
  align-items: center;
  gap: clamp(24px, 4.5vw, 67px);
  padding: 20px;
  border-radius: clamp(20px, 3.4vw, 36px);
  background: linear-gradient(125.7deg, #030e1d 12%, #000306 91.47%);
}

.services-page-art {
  flex: 1 1 40%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 360px;
  max-width: 532px;
  padding: 40px;
  background: rgba(244, 241, 234, 0.03);
  border-radius: clamp(18px, 2.8vw, 28px);
  overflow: hidden;
}

.services-page-content {
  flex: 1 1 55%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 48px;
}

.services-page-copy {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.services-page-heading {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(1.1rem, 1.7vw, 1.375rem);
  line-height: 1.5;
  color: #fff;
}

.services-page-text {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(0.95rem, 1.3vw, 1.25rem);
  line-height: 1.5;
  color: #fff;
}

.services-page-list {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(0.95rem, 1.3vw, 1.375rem);
  color: #fff;
}

.services-page-list-label {
  margin: 0 0 3px;
  line-height: 1.5;
}

.services-page-list ul {
  margin: 0;
  padding-left: 24px;
  line-height: 1.5;
}

.services-page-list li {
  margin-bottom: 4px;
}

.services-page-cta {
  align-self: flex-start;
  padding: 14px 16px;
  border-radius: 10px;
  background: var(--accent);
  color: var(--text);
  font-family: var(--font-body);
  font-weight: 800;
  font-size: clamp(0.95rem, 1.1vw, 1.125rem);
  text-decoration: none;
  transition: background 0.2s ease;
}

.services-page-cta:hover {
  background: var(--accent-hover);
}

@media (max-width: 1040px) {
  .services-page-tabs {
    gap: 6px;
  }
}

@media (max-width: 900px) {
  .services-page-tabs {
    display: none;
  }

  .services-page-dropdown {
    display: block;
  }

  .services-page-card-inner {
    flex-direction: column;
    align-items: stretch;
  }

  .services-page-art {
    max-width: 100%;
    min-height: 280px;
  }
}

@media (max-width: 640px) {
  .services-page {
    padding: 48px var(--container-pad) 72px;
  }

  .services-page-card {
    padding: 10px;
  }

  .services-page-card-inner {
    padding: 16px;
    gap: 32px;
  }

  .services-page-content {
    gap: 32px;
  }
}
