:root {
  --primary-color: #3B82F6;
  --secondary-color: #8B5CF6;
  --bg-color: #0B0F19;
  --surface-color: #111827;
  --text-main: #F8FAFC;
  --text-muted: #94A3B8;
  --border-color: #1E293B;
  --gradient-main: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
  --glass-bg: rgba(17, 24, 39, 0.8);
  --glass-border: rgba(255, 255, 255, 0.05);
  --shadow-sm: 0 4px 6px -1px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.5);
}

html {
  scroll-behavior: smooth;
}

/* Clear the fixed navbar when jumping to an anchor. The service rows are divs,
   not sections, but they are link targets too. */
section[id],
.wheel-panel[id] {
  scroll-margin-top: 7rem;
}

/* Lucide replaces every <i data-lucide> with an <svg> on DOMContentLoaded. An
   inline <i> has no box, so until the swap ran the icons occupied no space and
   the pages grew 26-122px underneath the user -- which also left in-page
   anchors scrolling to stale offsets. Reserve the box up front. The rules that
   set real icon sizes (.feature-icon, .trust-badge svg, inline width/height,
   ...) all come later or score higher, so they still win. */
[data-lucide] {
  display: inline-block;
  width: 24px;
  height: 24px;
  flex-shrink: 0;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: 'Inter', sans-serif;
  background-color: var(--bg-color);
  color: var(--text-main);
  overflow-x: hidden;
}

/* Navbar */
.navbar {
  position: fixed;
  top: 1rem;
  left: 50%;
  transform: translateX(-50%);
  width: 90%;
  max-width: 1400px;
  padding: 0.75rem 2rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  z-index: 1000;
  background: rgba(13, 18, 30, 0.94);
  border: 1px solid var(--border-color);
  border-radius: 50px;
  box-shadow: var(--shadow-sm);
  transition: all 0.3s ease;
}

.logo img {
  height: 48px;
  width: auto;
  transition: filter 0.3s ease;
}

[data-theme="dark"] .logo img {
  filter: drop-shadow(0 0 10px rgba(59, 130, 246, 0.3));
}

.nav-links {
  display: flex;
  gap: 2.5rem;
  align-items: center;
}

.nav-links a {
  text-decoration: none;
  color: var(--text-muted);
  font-size: 0.95rem;
  font-weight: 500;
  transition: color 0.2s;
}

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

.nav-actions {
  display: flex;
  gap: 1rem;
  align-items: center;
}

.theme-toggle {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-main);
  font-size: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem;
  border-radius: 50%;
  transition: background 0.2s;
}

.theme-toggle:hover {
  background: var(--border-color);
}

/* Hero Section */
.hero {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: space-between;
  text-align: left;
  padding: 10rem 5% 4rem;
  gap: 4rem;
  position: relative;
  overflow: hidden;
}

.hero-glow {
  position: absolute;
  bottom: -20%;
  left: 50%;
  transform: translateX(-50%);
  width: 150%;
  height: 60%;
  background: radial-gradient(ellipse at bottom, rgba(124, 58, 237, 0.4) 0%, rgba(37, 99, 235, 0.1) 40%, transparent 70%);
  z-index: 0;
  pointer-events: none;
}

.hero-content {
  flex: 1;
  max-width: 900px;
  z-index: 10;
}

.trust-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1.25rem;
  background: rgba(16, 185, 129, 0.1);
  border: 1px solid rgba(16, 185, 129, 0.2);
  border-radius: 50px;
  color: #10b981;
  font-weight: 600;
  font-size: 0.85rem;
  margin-bottom: 1.5rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.trust-badge svg,
.trust-badge [data-lucide] {
  width: 1.2em;
  height: 1.2em;
}

.hero-title {
  font-size: 3.8rem;
  font-weight: 800;
  line-height: 1.1;
  margin-bottom: 1.5rem;
  letter-spacing: -0.02em;
}

.gradient-text {
  background: var(--gradient-main);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  display: inline-block;
}

.hero-subtitle {
  font-size: 1.1rem;
  color: var(--text-muted);
  margin: 0 auto 2.5rem;
  max-width: 80%;
  line-height: 1.6;
}

.hero-actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
  align-items: center;
}

.trust-markers {
  position: absolute;
  bottom: 2rem;
  /* Centred with auto margins, NOT translateX(-50%): this element also carries a
     reveal variant, and landing that variant sets transform:none -- which would
     silently drop the centering and shunt the row to the right. */
  left: 0;
  right: 0;
  margin-inline: auto;
  display: flex;
  gap: 3rem;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  /* max-content keeps the two markers on one line on desktop; the cap lets them
     wrap on phones instead of forcing the page wider than the viewport. */
  width: max-content;
  max-width: 90vw;
  z-index: 20;
}

.trust-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: #10b981;
  font-size: 0.95rem;
  font-weight: 600;
}

.trust-item svg,
.trust-item [data-lucide] {
  width: 1.2em;
  height: 1.2em;
  stroke-width: 2.5;
}

.btn {
  padding: 1rem 2.5rem;
  border-radius: 50px;
  font-weight: 600;
  font-size: 1rem;
  text-decoration: none;
  transition: all 0.3s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.btn-arrow .arrow {
  margin-left: 0.5rem;
  transition: transform 0.3s ease;
}

.btn-arrow:hover .arrow {
  transform: translateX(6px);
}

.btn-sm {
  padding: 0.6rem 1.5rem;
  font-size: 0.9rem;
}

.btn-primary {
  background: var(--gradient-main);
  color: white;
  box-shadow: 0 8px 25px -5px rgba(124, 58, 237, 0.4);
  border: none;
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 15px 30px -5px rgba(124, 58, 237, 0.6);
}

.btn-outline {
  background: rgba(255, 255, 255, 0.02);
  color: var(--text-main);
  /* --border-color is near-black against the page; too faint to read as a button. */
  border: 1px solid rgba(255, 255, 255, 0.14);
}

.btn-outline:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.28);
}

.btn-submit-fill {
  background: var(--surface-color);
  color: #10b981;
  border: 1px solid rgba(16, 185, 129, 0.3);
  position: relative;
  overflow: hidden;
  z-index: 1;
}

.btn-submit-fill::before {
  content: '';
  position: absolute;
  top: 0;
  left: -10%;
  width: 0%;
  height: 100%;
  background: #10b981;
  z-index: -1;
  transition: width 0.4s cubic-bezier(0.25, 1, 0.5, 1);
  transform: skewX(-15deg);
}

.btn-submit-fill:hover::before {
  width: 120%;
}

.btn-submit-fill:hover {
  color: white;
  border-color: #10b981;
  box-shadow: 0 10px 25px -5px rgba(16, 185, 129, 0.4);
  transform: translateY(-2px);
}


/* Hero Metrics UI */
.hero-metrics {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2rem;
  z-index: 10;
  position: relative;
  max-width: 500px;
}

.metric-card {
  background: rgba(17, 24, 39, 0.92);
  border: 1px solid color-mix(in srgb, var(--card-color, rgba(255, 255, 255, 0.08)) 30%, transparent);
  border-radius: 20px;
  padding: 1.25rem;
  box-shadow: 0 10px 30px -10px color-mix(in srgb, var(--card-color, transparent) 15%, transparent);
}

.metric-card.card-1 {
  align-self: flex-start;
  width: 80%;
}

.metric-card.card-2 {
  align-self: flex-end;
  width: 75%;
}

.metric-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.5rem;
}

.metric-header .metric-value {
  color: var(--card-color, #10b981);
  font-weight: 700;
  font-size: 1.1rem;
}

.metric-title {
  color: var(--text-main);
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 1rem;
}

.metric-big-value {
  font-size: 2rem;
  font-weight: 800;
  margin-bottom: 1rem;
  color: var(--card-color, var(--primary-color));
}

/* Pulse Dot */
.pulse-dot {
  width: 12px;
  height: 12px;
  background-color: var(--card-color, #10b981);
  border-radius: 50%;
  position: relative;
}

.pulse-dot::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--card-color, #10b981);
  /* Its parent card also animates, so without an explicit layer this ring is
     re-rasterised into the card every frame instead of just composited. */
  will-change: transform, opacity;
  animation: pulse-ring 2.6s infinite cubic-bezier(0.66, 0, 0, 1);
}

@keyframes pulse-ring {
  from { transform: scale(1); opacity: 0.55; }
  to { transform: scale(2.1); opacity: 0; }
}

/* Animated Bar Chart */
.bar-chart {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.5rem;
  height: 60px;
}

.bar {
  flex: 1;
  background: var(--card-color, var(--primary-color));
  border-radius: 4px 4px 0 0;
  transform-origin: bottom;
  animation: bar-grow 900ms var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1)) both;
}

.bar-1 { height: 40%; animation-delay: 0.05s; opacity: 0.6; }
.bar-2 { height: 60%; animation-delay: 0.12s; opacity: 0.7; }
.bar-3 { height: 35%; animation-delay: 0.19s; opacity: 0.8; }
.bar-4 { height: 80%; animation-delay: 0.26s; opacity: 0.9; }
.bar-5 { height: 100%; animation-delay: 0.33s; opacity: 1; }

@keyframes bar-grow {
  from { transform: scaleY(0.15); }
  to { transform: scaleY(1); }
}

/* Progress Bar */
.progress-bar-bg {
  width: 100%;
  height: 8px;
  background: rgba(124, 58, 237, 0.1);
  border-radius: 999px;
  overflow: hidden;
}

.progress-bar-fill {
  height: 100%;
  background: var(--card-color, var(--gradient-main));
  border-radius: 999px;
  width: 0%;
  animation: progress-fill 2s ease-out forwards;
}

@keyframes progress-fill {
  to { width: 99.99%; }
}

@keyframes float-up-down {
  0% { transform: translateY(0); }
  100% { transform: translateY(-15px); }
}

/* Hero Motions */
.hero-motions {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

.motion-shape {
  position: absolute;
  border-radius: 50%;
  opacity: 0.5;
  background: radial-gradient(circle closest-side, var(--shape-color, var(--primary-color)), transparent);
  z-index: -1;
}

.shape-1 {
  width: 520px;
  height: 520px;
  --shape-color: var(--primary-color);
  top: 10%;
  left: 20%;
  animation-delay: 0s;
}

.shape-2 {
  width: 460px;
  height: 460px;
  --shape-color: var(--secondary-color);
  bottom: 20%;
  right: 10%;
  animation-delay: -3s;
}

.shape-3 {
  width: 380px;
  height: 380px;
  --shape-color: #38bdf8;
  top: 40%;
  left: 50%;
  animation-delay: -6s;
}

@keyframes float-around {
  0% { transform: translate(0, 0); }
  33% { transform: translate(30px, -50px); }
  66% { transform: translate(-40px, 20px); }
  100% { transform: translate(20px, 40px); }
}

/* Professional Services Section */
.services-section-professional {
  padding: 8rem 5%;
  background: var(--bg-color);
  position: relative;
  border-top: 1px solid var(--glass-border);
  /* Contains the decorative header glow without clipping the cards' 3D hover
     shadows the way overflow:hidden would. */
  overflow-x: clip;
}

.services-grid {
  display: grid;
  /* min() so the track can drop below 320px rather than overflow narrow phones. */
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 1.25rem;
  max-width: 1300px;
  margin: 0 auto;
  perspective: 1200px;
}

.service-card {
  background: rgba(20, 27, 43, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 24px;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  transition: border-color 0.3s ease, transform 0.1s ease-out;
  box-shadow: var(--shadow-sm);
  position: relative;
}

.service-card:hover {
  border-color: var(--card-color, rgba(255,255,255,0.2));
}

.service-card > * {
  position: relative;
  z-index: 2;
}

.service-card-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1rem;
}

.service-icon {
  font-size: 1.25rem;
  background: color-mix(in srgb, var(--card-color) 10%, var(--glass-bg));
  color: var(--card-color, var(--text-main));
  padding: 0.6rem;
  border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--card-color) 25%, var(--glass-border));
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--card-color) 20%, transparent);
  display: inline-flex;
  transition: transform 0.3s ease, border-color 0.3s ease;
}

.service-icon svg,
.service-icon [data-lucide] {
  width: 1em;
  height: 1em;
  stroke-width: 1.5;
}

.service-card:hover .service-icon {
  transform: translateY(-5px);
  border-color: var(--card-color);
  box-shadow: 0 8px 16px -2px color-mix(in srgb, var(--card-color) 40%, transparent);
}

.service-card-content {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.service-card-footer {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-top: auto;
}

.tech-tag {
  display: inline-flex;
  align-items: center;
  padding: 0.4rem 0.8rem;
  background: color-mix(in srgb, var(--card-color) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-color) 30%, transparent);
  border-radius: 50px;
  color: var(--card-color);
  font-weight: 700;
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.card-metric {
  margin-top: 1rem;
  margin-bottom: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.metric-value {
  font-size: 1.75rem;
  font-weight: 800;
  color: var(--card-color);
  letter-spacing: -0.02em;
}

.metric-label {
  font-size: 0.8rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}

.service-title {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--text-main);
}

.service-desc {
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}

.explore-link {
  display: inline-flex;
  align-items: center;
  margin-top: 0;
  font-weight: 600;
  color: var(--primary-color);
  text-decoration: none;
  font-size: 0.95rem;
  transition: all 0.3s ease;
}

.service-desc strong {
  color: var(--text-main);
  font-weight: 600;
}

.explore-link .arrow {
  margin-left: 0.5rem;
  transition: transform 0.3s ease;
}

.explore-link:hover {
  color: var(--text-main);
}

.explore-link:hover .arrow {
  transform: translateX(4px);
}

/* Showcase Section Premium */
.showcase-section-premium {
  padding: 10rem 5%;
  background: var(--bg-color);
  border-top: 1px solid var(--glass-border);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  position: relative;
  overflow: hidden;
}

.showcase-header {
  max-width: 800px;
  margin-bottom: 6rem;
  position: relative;
  z-index: 2;
}

.tech-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1.25rem;
  background: rgba(16, 185, 129, 0.1);
  border: 1px solid rgba(16, 185, 129, 0.2);
  border-radius: 50px;
  color: #10b981;
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 1.5rem;
}

.showcase-visuals {
  position: relative;
  width: 100%;
  max-width: 1100px;
  height: 500px;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-bottom: 4rem;
}

.glow-bg {
  position: absolute;
  width: 400px;
  height: 400px;
  border-radius: 50%;
  z-index: 0;
  pointer-events: none;
}

.glow-1 {
  background: radial-gradient(circle closest-side, var(--primary-color), transparent);
  opacity: 0.3;
  top: 50%;
  left: 30%;
  transform: translate(-50%, -50%);
}

.glow-2 {
  background: radial-gradient(circle closest-side, var(--secondary-color), transparent);
  opacity: 0.3;
  top: 50%;
  right: 30%;
  transform: translate(50%, -50%);
}

.glass-window {
  position: absolute;
  background: rgba(15, 23, 42, 0.94);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  z-index: 1;
  transition: transform 0.5s ease;
}

.window-bar {
  display: flex;
  gap: 6px;
  padding: 12px 16px;
  background: rgba(0, 0, 0, 0.2);
  border-bottom: 1px solid var(--glass-border);
}

.window-bar .dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
}
.dot.red { background: #ef4444; }
.dot.yellow { background: #f59e0b; }
.dot.green { background: #10b981; }

.window-left {
  width: 450px;
  left: 5%;
  transform: translateY(-20px) rotate(-2deg);
  z-index: 1;
}

.window-right {
  width: 500px;
  right: 5%;
  transform: translateY(20px) rotate(2deg);
  z-index: 2;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}

.window-left:hover {
  transform: translateY(-30px) rotate(0deg);
  z-index: 3;
}

.window-right:hover {
  transform: translateY(10px) rotate(0deg);
}

.floating-metric {
  position: absolute;
  bottom: 0;
  left: 2%;
  z-index: 3;
  background: var(--surface-color);
  border: 1px solid var(--glass-border);
  padding: 1rem 1.5rem;
  border-radius: 16px;
  display: flex;
  align-items: center;
  gap: 1rem;
  box-shadow: var(--shadow-lg);
}

.floating-metric h4 {
  font-size: 1.25rem;
  font-weight: 800;
  color: var(--text-main);
  line-height: 1;
  margin-bottom: 4px;
}
.floating-metric span {
  font-size: 0.85rem;
  color: var(--text-muted);
}

/* Contact Section */
.contact-section {
  padding: 8rem 5%;
  background: var(--surface-color);
  border-top: 1px solid var(--border-color);
}

.contact-container {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  gap: 6rem;
  align-items: center;
}

.contact-info {
  flex: 1;
}

.contact-details {
  margin-top: 3rem;
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.detail-item {
  display: flex;
  gap: 1.5rem;
  align-items: flex-start;
}

.detail-icon {
  font-size: 1.5rem;
  background: var(--bg-color);
  padding: 1rem;
  border-radius: 12px;
  border: 1px solid var(--glass-border);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--primary-color);
}

.detail-icon svg,
.detail-icon [data-lucide] {
  width: 1.25em;
  height: 1.25em;
  stroke-width: 1.5;
}

.detail-item h4 {
  font-size: 1.1rem;
  color: var(--text-main);
  margin-bottom: 0.25rem;
}

.detail-item p {
  color: var(--text-muted);
  line-height: 1.6;
}

.contact-form-wrapper {
  flex: 1;
  background: var(--bg-color);
  padding: 3rem;
  border-radius: 24px;
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-sm);
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}

/* Case study page. One column, measured for reading rather than scanning --
   the rest of the site is a shopfront, this page is prose. */
.case-study {
  max-width: 780px;
  margin: 0 auto;
  padding: 11rem 5% 2rem;
}

.case-back {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.9rem;
  display: inline-block;
  margin-bottom: 2.5rem;
}

.case-back:hover { color: var(--text-main); }

.case-icon {
  width: 72px;
  height: 72px;
  border-radius: 18px;
  border: 1px solid;
  display: grid;
  place-items: center;
  margin-bottom: 1.75rem;
}

.case-study h1 {
  font-size: 3rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.1;
}

.case-client {
  color: var(--text-muted);
  font-size: 1rem;
  margin-top: 0.75rem;
}

.case-summary {
  font-size: 1.2rem;
  line-height: 1.7;
  color: var(--text-muted);
  margin: 1.5rem 0 2rem;
}

.case-meta {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  align-items: center;
  padding-bottom: 2.5rem;
  border-bottom: 1px solid var(--border-color);
}

.case-metric {
  padding: 0.35rem 0.9rem;
  border-radius: 50px;
  border: 1px solid;
  font-weight: 600;
  font-size: 0.85rem;
}

.case-body {
  padding: 2.5rem 0;
}

.case-body p {
  font-size: 1.05rem;
  line-height: 1.85;
  color: var(--text-main);
  margin-bottom: 1.5rem;
}

.case-services {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  align-items: center;
  padding-top: 2rem;
  border-top: 1px solid var(--border-color);
}

.case-services span {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.case-services a {
  color: var(--primary-color);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
}

.case-services a:hover { text-decoration: underline; }

@media (max-width: 640px) {
  .case-study { padding-top: 8rem; }
  .case-study h1 { font-size: 2.1rem; }
  .case-summary { font-size: 1.05rem; }
}

/* The email and phone in the contact block are real links now. Without this
   they render in the browser's default blue, which is unreadable on the dark
   surface and ignores the rest of the palette. */
.detail-item a {
  color: inherit;
  text-decoration: none;
  transition: color 0.2s;
}

.detail-item a:hover {
  color: var(--primary-color);
}

/* Injected by script.js above the contact form when the server rejects a
   submission or the network fails. Absent from the markup until then. */
.form-error {
  display: none;
  padding: 0.85rem 1.15rem;
  border-radius: 12px;
  background: rgba(248, 113, 113, 0.1);
  border: 1px solid rgba(248, 113, 113, 0.3);
  color: #FCA5A5;
  font-size: 0.9rem;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.form-group label {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--text-main);
}

.form-group input,
.form-group textarea,
.form-group select {
  width: 100%;
  padding: 1rem 1.25rem;
  border-radius: 12px;
  background: var(--surface-color);
  border: 1px solid var(--glass-border);
  color: var(--text-main);
  font-family: inherit;
  font-size: 1rem;
  transition: border-color 0.3s;
}

.form-group select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%239CA3AF%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpolyline%20points%3D%226%209%2012%2015%2018%209%22%3E%3C%2Fpolyline%3E%3C%2Fsvg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 1rem;
}
.form-group select:invalid {
  color: var(--text-muted);
}

.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
  outline: none;
  border-color: var(--primary-color);
}

.form-success {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 3rem;
  background: var(--surface-color);
  border-radius: 20px;
  border: 1px solid rgba(16, 185, 129, 0.2);
}

.form-success h3 {
  font-size: 1.5rem;
  color: var(--text-main);
  margin-bottom: 0.5rem;
}

.form-success p {
  color: var(--text-muted);
  margin-bottom: 2rem;
}

/* Footer */
.site-footer {
  background: var(--bg-color);
  padding: 6rem 5% 2rem;
  border-top: 1px solid var(--glass-border);
}

.footer-top {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  gap: 4rem;
  flex-wrap: wrap;
  padding-bottom: 4rem;
  border-bottom: 1px solid var(--glass-border);
}

.footer-brand {
  flex: 2;
  min-width: 300px;
}

.footer-brand p {
  margin-top: 1.5rem;
  color: var(--text-muted);
  line-height: 1.6;
  max-width: 400px;
}

.footer-links {
  flex: 1;
  min-width: 150px;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.footer-links h4 {
  font-size: 1.1rem;
  color: var(--text-main);
  margin-bottom: 0.5rem;
}

.footer-links a {
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.3s;
}

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

.footer-bottom {
  max-width: 1200px;
  margin: 2rem auto 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: var(--text-muted);
  font-size: 0.95rem;
}

.social-links {
  display: flex;
  gap: 1.5rem;
}

.social-links a {
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.3s;
}

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

/* --- Services Page Styles --- */
.page-hero {
  position: relative;
  overflow: hidden;
}

.service-row {
  display: flex;
  align-items: flex-start;
  gap: 4rem;
  margin-bottom: 8rem;
}

.service-row.row-reverse {
  flex-direction: row-reverse;
}

.service-sticky-sidebar {
  flex: 1;
  position: sticky;
  top: 120px;
}

.service-content-scroll {
  flex: 1.2;
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.service-feature-card {
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 24px;
  padding: 2.5rem;
  transition: transform 0.3s, box-shadow 0.3s;
  position: relative;
  overflow: hidden;
}

.service-feature-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at top right, rgba(255,255,255,0.03), transparent);
  opacity: 0;
  transition: opacity 0.3s;
}

.service-feature-card:hover::before {
  opacity: 1;
}

.service-feature-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 20px 40px -10px rgba(0,0,0,0.5);
  border-color: rgba(255,255,255,0.1);
}

.feature-icon {
  width: 48px;
  height: 48px;
  margin-bottom: 1.5rem;
}

.service-feature-card h3 {
  font-size: 1.5rem;
  margin-bottom: 1rem;
}

.service-feature-card p {
  color: var(--text-muted);
  line-height: 1.7;
}

/* Responsive */
@media (max-width: 992px) {
  .hero {
    flex-direction: column;
    text-align: center;
    padding-top: 8rem;
  }
  .hero-title {
    font-size: 3.5rem;
  }
  .hero-subtitle {
    margin: 0 auto 2.5rem;
  }
  .bento-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .card-geo, .card-custom, .card-aiauto, .card-aisol, .card-ui, .card-web, .card-aws {
    grid-column: span 2;
  }
  .showcase-section {
    flex-direction: column-reverse;
  }
  
  .service-row, .service-row.row-reverse {
    flex-direction: column;
    gap: 2rem;
  }
  .service-sticky-sidebar {
    position: relative;
    top: 0;
  }
}

/* The contact block is a two-column flex row on desktop; it had no breakpoint,
   so on phones it stayed side by side and pushed the whole page wider than the
   viewport. Stack it instead. */
@media (max-width: 900px) {
  .contact-container {
    flex-direction: column;
    gap: 3rem;
    align-items: stretch;
  }
  .contact-form-wrapper {
    padding: 2rem;
  }
  .footer-bottom {
    flex-direction: column;
    gap: 1rem;
    text-align: center;
  }
}

@media (max-width: 576px) {
  .bento-grid {
    grid-template-columns: 1fr;
  }
  .bento-card {
    grid-column: span 1 !important;
  }
  .form-row {
    grid-template-columns: 1fr;
  }
  .contact-form-wrapper {
    padding: 1.5rem;
  }
}

/* Animations */
.fade-in-up {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.fade-in-up.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ==========================================================================
   3D motion in the layout itself
   ========================================================================== */

/* A hinging card projects wider than its layout box (its near edge is closer
   to the camera), which can push the page wider than the viewport on narrow
   screens. Clip horizontally — unlike overflow:hidden this neither creates a
   scroll container nor cuts off the cards' vertical hover shadows. */
.showcase-grid-section,
.values-section,
.services-grid {
  overflow-x: clip;
}



















/* ==========================================================================
   Chrome: scroll progress + condensed navbar
   ========================================================================== */

.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: var(--gradient-main);
  transform: scaleX(0);
  transform-origin: 0 50%;
  z-index: 1100;
  pointer-events: none;
}

.navbar.scrolled {
  padding: 0.5rem 1.75rem;
  background: rgba(11, 15, 25, 0.88);
  border-color: rgba(255, 255, 255, 0.12);
  box-shadow: 0 12px 40px -14px rgba(0, 0, 0, 0.8);
}

.navbar.scrolled .logo img {
  height: 38px;
}

/* Animated brand gradient. */
.gradient-text {
  background: linear-gradient(
    120deg,
    var(--primary-color),
    var(--secondary-color),
    #22d3ee,
    var(--primary-color)
  );
  background-size: 100% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* The two showcase windows are absolutely positioned for the overlapping desktop
   composition; below this width they stack in normal flow instead. */
@media (max-width: 900px) {
  .showcase-visuals {
    height: auto;
    flex-direction: column;
    gap: 2rem;
  }
  .glass-window {
    position: relative;
    left: auto;
    right: auto;
    width: 100%;
    max-width: 520px;
    transform: none;
  }
  .window-left:hover,
  .window-right:hover {
    transform: translateY(-6px);
  }
  .floating-metric {
    position: relative;
    bottom: auto;
    left: auto;
  }
}

/* Below 992px the hero stacks and the copy centres over the scene, so the core
   gets the same fade-behind-the-text treatment as the sub-page heroes. */
@media (max-width: 992px) {
  .hero .scene-canvas {
    -webkit-mask-image: radial-gradient(
      ellipse 62% 42% at 50% 46%,
      rgba(0, 0, 0, 0.14) 0%,
      rgba(0, 0, 0, 0.5) 60%,
      #000 100%
    );
    mask-image: radial-gradient(
      ellipse 62% 42% at 50% 46%,
      rgba(0, 0, 0, 0.14) 0%,
      rgba(0, 0, 0, 0.5) 60%,
      #000 100%
    );
  }
  .hero .scene-canvas.is-ready {
    opacity: 0.75;
  }
}

/* Phone typography and stacked actions. !important is needed because several
   headings carry inline font-size values in the markup. */
@media (max-width: 640px) {
  .hero-title {
    font-size: 2.6rem !important;
  }
  .section-title {
    font-size: 2.1rem !important;
  }
  .hero-subtitle {
    font-size: 1rem !important;
  }
  .hero-actions {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }
  .hero-actions .btn {
    width: 100%;
  }
  .btn {
    padding: 0.9rem 1.75rem;
  }
  .metric-card.card-1,
  .metric-card.card-2 {
    width: 100%;
    align-self: stretch;
  }
  .hero-metrics {
    max-width: 100%;
  }
  .showcase-filters .btn {
    font-size: 0.85rem;
    padding: 0.6rem 1.1rem;
  }
}

/* ==========================================================================
   Mobile navigation
   ========================================================================== */

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 0 10px;
  background: none;
  border: none;
  cursor: pointer;
  z-index: 1060;
}

.nav-toggle span {
  display: block;
  height: 2px;
  width: 100%;
  border-radius: 2px;
  background: var(--text-main);
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.2s ease;
}

.nav-toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 1050;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.5rem;
  padding: 6rem 2rem 3rem;
  background: rgba(8, 11, 20, 0.94);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  /* The links hinge in on the Z axis, so the drawer needs depth. */
  perspective: 900px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s ease, visibility 0s linear 0.35s;
}

.mobile-menu.open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.35s ease, visibility 0s;
}

.mobile-menu-links {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.75rem;
}

.mobile-menu-links a {
  font-size: 1.9rem;
  font-weight: 700;
  color: var(--text-main);
  text-decoration: none;
  letter-spacing: -0.02em;
  transform-origin: 50% 0;
  transform: rotateX(-75deg) translateY(14px);
  opacity: 0;
  transition: transform 0.55s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.4s ease,
    color 0.2s ease;
}

.mobile-menu.open .mobile-menu-links a {
  transform: rotateX(0deg) translateY(0);
  opacity: 1;
}

.mobile-menu.open .mobile-menu-links a:nth-child(1) { transition-delay: 0.08s; }
.mobile-menu.open .mobile-menu-links a:nth-child(2) { transition-delay: 0.14s; }
.mobile-menu.open .mobile-menu-links a:nth-child(3) { transition-delay: 0.2s; }
.mobile-menu.open .mobile-menu-links a:nth-child(4) { transition-delay: 0.26s; }

.mobile-menu-links a.is-current,
.mobile-menu-links a:hover {
  color: var(--primary-color);
}

.mobile-menu-actions {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: 100%;
  max-width: 320px;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.4s ease 0.3s, transform 0.5s ease 0.3s;
}

.mobile-menu.open .mobile-menu-actions {
  opacity: 1;
  transform: none;
}

.mobile-menu-actions .btn {
  width: 100%;
}

/* Locked while the drawer is open so the page behind doesn't scroll. */
body.menu-open {
  overflow: hidden;
}

/* .nav-toggle's own z-index can't lift it above the drawer, because .navbar
   establishes a stacking context. Raise the whole bar instead, stripped back to
   just the logo and the close button floating over the overlay. */
body.menu-open .navbar {
  z-index: 1060;
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Swap the inline nav for the drawer once the links stop fitting. */
@media (max-width: 860px) {
  .navbar {
    width: 94%;
    padding: 0.6rem 0.75rem 0.6rem 1.25rem;
  }
  .nav-links,
  .nav-actions {
    display: none;
  }
  .nav-toggle {
    display: flex;
  }
}

@media (min-width: 861px) {
  .mobile-menu {
    display: none;
  }
}

/* Respect the OS "reduce motion" setting across every decorative animation. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .gradient-text,
  .metric-card,
  .motion-shape,
  .bar,
  .pulse-dot,
  .floating-metric,
  .progress-bar-fill {
    animation: none !important;
  }
  .fade-in-up {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .progress-bar-fill {
    width: 99.99%;
  }
}


/* ==========================================================================
   Capabilities: extruded 3D card layout
   Everything here animates transform and opacity only, so it runs on the
   compositor -- no filters, no backdrop blur, no per-frame repaints.
   ========================================================================== */



/* Back plate, pushed away on Z. When the card tilts, this reads as the solid
   side of a slab rather than a flat rectangle turning. */
.service-card::after {
  content: '';
  position: absolute;
  inset: 6px -6px -10px 6px;
  border-radius: 24px;
  background: linear-gradient(
    160deg,
    color-mix(in srgb, var(--card-color) 30%, transparent),
    rgba(8, 11, 20, 0.9) 60%
  );
  border: 1px solid color-mix(in srgb, var(--card-color) 22%, transparent);
  transition: opacity 0.35s ease;
  opacity: 0.5;
  pointer-events: none;
  z-index: -1;
}

.service-card:hover::after {
  transform: scale(1.015);
  opacity: 0.9;
}

/* Icon tile gets real thickness. */
.service-icon {
  position: relative;
}

.service-icon::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 12px;
  background: color-mix(in srgb, var(--card-color) 45%, rgba(8, 11, 20, 0.9));
  transition: opacity 0.3s ease;
  opacity: 0.75;
  z-index: -1;
}


@media (prefers-reduced-motion: reduce) {
  .service-card::after,
  .service-icon::before {
    transform: none;
  }
}


/* ==========================================================================
   Card hover
   transform-style stays FLAT at all times. Toggling it to preserve-3d on hover
   made every child's translateZ snap into effect at once (a visible pop in and
   out) and forced the card's whole rendering context to be rebuilt on each
   enter/leave. The depth now comes from the card's own tilt plus the slab's
   X/Y offset, which needs no 3D context at all.
   ========================================================================== */

/* Brightens on hover. The static offset already reads as extrusion, so nothing
   here needs to move. */
.service-card:hover::after {
  opacity: 1;
}

.service-card:hover .service-icon {
  transform: translateY(-5px);
}

.service-card:hover .service-icon::before {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .service-card:hover .service-icon {
    transform: none;
  }
}


/* ==========================================================================
   Founders
   Same extruded-slab construction as the capability cards: the depth is a
   static offset on a ::after plate, and hover only changes opacity, so nothing
   here repaints per frame. The lift itself lives in motion.css.
   ========================================================================== */

.founder-grid {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  /* 4-up needs to fit 1200px minus the section's 5% padding: 4 x 230 + 3 x 28
     leaves room to spare. A larger minimum wraps the row to 2 + 2. */
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  gap: 2.5rem 1.75rem;
}

.founder-card {
  position: relative;
  background: rgba(20, 27, 43, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 24px;
  padding: 2rem 1.5rem 1.75rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  box-shadow: var(--shadow-sm);
}

.founder-card:hover {
  border-color: color-mix(in srgb, var(--card-color) 55%, transparent);
}

/* The slab. Offset down/right so the card reads as a solid object at rest. */
.founder-card::after {
  content: '';
  position: absolute;
  inset: 6px -6px -10px 6px;
  border-radius: 24px;
  background: linear-gradient(
    160deg,
    color-mix(in srgb, var(--card-color) 30%, transparent),
    rgba(8, 11, 20, 0.9) 60%
  );
  border: 1px solid color-mix(in srgb, var(--card-color) 22%, transparent);
  transition: opacity 0.35s ease;
  opacity: 0.5;
  pointer-events: none;
  z-index: -1;
}

.founder-card:hover::after {
  opacity: 1;
}

/* Monogram plate. Swap the .founder-monogram span for an <img> when real
   portraits land -- the plate, ring and thickness all still apply. */
.founder-avatar {
  position: relative;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1.35rem;
  background: color-mix(in srgb, var(--card-color) 14%, var(--glass-bg));
  border: 1px solid color-mix(in srgb, var(--card-color) 35%, var(--glass-border));
  box-shadow: 0 6px 18px -6px color-mix(in srgb, var(--card-color) 45%, transparent);
  transition: transform 0.3s ease, border-color 0.3s ease;
}

/* Thickness under the plate, same trick as .service-icon::before. */
.founder-avatar::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: color-mix(in srgb, var(--card-color) 45%, rgba(8, 11, 20, 0.9));
  transform: translate(3px, 4px);
  transition: opacity 0.3s ease;
  opacity: 0.8;
  z-index: -1;
}

.founder-card:hover .founder-avatar {
  transform: translateY(-4px);
  border-color: var(--card-color);
}

.founder-card:hover .founder-avatar::before {
  opacity: 1;
}

.founder-monogram {
  font-size: 1.65rem;
  font-weight: 800;
  letter-spacing: 1px;
  color: var(--card-color);
}

.founder-avatar img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

.founder-name {
  font-size: 1.3rem;
  font-weight: 700;
  margin-bottom: 0.35rem;
}

.founder-role {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--card-color);
  margin-bottom: 1rem;
}

.founder-bio {
  color: var(--text-muted);
  font-size: 0.95rem;
  line-height: 1.65;
  margin-bottom: 1.35rem;
}

.founder-tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem;
  margin-top: auto;
}

.founder-tag {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  color: var(--text-muted);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.09);
}

@media (max-width: 600px) {
  .founder-grid { gap: 2rem 1.25rem; }
  .founder-card { padding: 1.75rem 1.25rem 1.5rem; }
  .founder-avatar { width: 80px; height: 80px; }
}

@media (prefers-reduced-motion: reduce) {
  .founder-card:hover .founder-avatar { transform: none; }
}

/* ==========================================================================
   Services drum
   Eight panels tile a cylinder: panel i sits at rotateX(i * 45deg)
   translateZ(R), and the drum counter-rotates to bring one flat to the viewer.
   R = (panelHeight / 2) / tan(22.5deg) is the radius at which 8 panels of that
   height meet edge to edge -- any smaller and they intersect, any larger and
   gaps open between them.

   Only the active panel and its two neighbours are painted; everything else is
   visibility:hidden, so a spin rasterises three panels rather than eight.
   ========================================================================== */

.wheel-section {
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem 5% 6rem;
}

.wheel-layout {
  display: grid;
  grid-template-columns: 232px 1fr;
  gap: 3rem;
  align-items: center;
}

/* ---- rail ---- */

.wheel-rail {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.wheel-rail-heading {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.85rem;
}

.wheel-rail button {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  padding: 0.6rem 0.5rem 0.6rem 0.9rem;
  background: none;
  border: 0;
  border-left: 2px solid transparent;
  border-radius: 0 8px 8px 0;
  color: var(--text-muted);
  font: inherit;
  font-size: 0.92rem;
  text-align: left;
  cursor: pointer;
  transition: color 0.25s ease, border-color 0.25s ease, background 0.25s ease;
}

.wheel-rail button:hover {
  color: var(--text-main);
  background: rgba(255, 255, 255, 0.03);
}

.wheel-rail button.is-active {
  color: var(--text-main);
  font-weight: 600;
  border-left-color: var(--card-color, var(--primary-color));
  background: rgba(255, 255, 255, 0.04);
}

.wheel-rail-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
  flex-shrink: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.wheel-rail button.is-active .wheel-rail-dot {
  background: var(--card-color, var(--primary-color));
  opacity: 1;
  transform: scale(1.35);
}

/* ---- drum ---- */

.wheel-window {
  /* The panels are absolutely positioned, so the browser scrolling to one of
     them is not a reliable way to frame the drum. wheel.js scrolls this box
     instead, and this keeps it clear of the fixed navbar. */
  scroll-margin-top: 7rem;
  --ph: 700px;
  --step: 45deg;
  /* (ph / 2) / tan(22.5deg) */
  --r: calc(var(--ph) * 1.2071);
  position: relative;
  height: 840px;
  /* clip, not hidden: an overflow:hidden box is still a scroll container, and
     the browser jumping to a #service fragment scrolled this one down by the
     panel offset -- which pushed the panel above the window clean out of
     sight. overflow:clip cannot be scrolled. hidden stays as the fallback. */
  overflow: hidden;
  overflow: clip;
  /* Vertical swipes must still scroll the page on a phone, so touch drags spin
     the drum horizontally instead. See the note in wheel.js. */
  touch-action: pan-y;
  outline: none;
}

.wheel-window:focus-visible {
  box-shadow: 0 0 0 2px var(--primary-color);
  border-radius: 26px;
}

/* Just a positioning box.

   It used to be the cylinder itself: transform-style:preserve-3d, with the eight
   panels placed around it at rotateX(i * 45deg) translateZ(R) and this element
   counter-rotating to bring one to the front. That is the textbook drum, and it
   could not be made to perform. Chromium would not composite the rotation of a
   preserve-3d scene containing eight large panels, so every frame of every spin
   went through the main thread: 1212ms of style recalculation across seven
   spins, 63% of frames missed at 4x CPU throttle. Shrinking the panels, hiding
   the far ones, promoting the layer and removing the custom property from the
   transform each bought a few points and none came close.

   So there is no shared 3D scene any more. Each panel carries its own
   perspective() and tilts independently between three fixed states, which is an
   ordinary transform + opacity transition and composites like any other. It
   looks the same; it costs almost nothing. */
.wheel-drum {
  position: absolute;
  inset: 0;
}

.wheel-panel {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(50% - var(--ph) / 2);
  height: var(--ph);
  background: rgba(17, 23, 37, 0.96);
  border: 1px solid color-mix(in srgb, var(--card-color) 26%, var(--glass-border));
  border-radius: 26px;
  padding: 2.5rem 2.75rem;
  box-shadow: var(--shadow-sm);
  overflow-y: hidden;
  /* No overscroll-behavior:contain. A panel that overflows becomes a scroll
     container, and containing the overscroll meant the mouse wheel died inside
     it instead of moving the page -- the panel had 51px to give at ~1000px wide
     and then simply swallowed the gesture. Chaining is the right default. */
  scrollbar-width: thin;
  transition: transform 380ms var(--ease-spring), opacity 260ms ease;
}

/* perspective() has to come first in the list; it applies to what follows.

   The offset is 68%, not the 88% that looks right on paper. Tilting by 58deg
   and scaling to 0.88 shrinks a panel projected height to about
   (h/2) * cos(58deg) * 0.88, so at 88% the neighbours clear the window
   entirely -- invisible, and nothing to click. 63% lines each neighbour up with
   the band of window left over above and below the active panel. */
.wheel-panel.is-below,
.wheel-panel.is-far {
  transform: perspective(1400px) translateY(63%) rotateX(-58deg) scale(0.88);
}

.wheel-panel.is-above {
  transform: perspective(1400px) translateY(-63%) rotateX(58deg) scale(0.88);
}

.wheel-panel.is-active {
  transform: perspective(1400px) translateY(0) rotateX(0deg) scale(1);
}

/* A panel on its way out of view fades but does not animate its tilt: it is
   behind the neighbour and about to be invisible, and every panel that
   animates is another one being re-rasterised for the length of the step. */
.wheel-panel.is-far { transition: opacity 260ms ease; }

/* Jumping straight to a service from a link should not animate through it. */
.wheel-panel.is-instant { transition: none; }

/* Every state rule below is keyed on a class on the element it styles, never on
   an ancestor's state. That is deliberate. The first version drove these from
   `.wheel-drum:not(.is-spinning) .wheel-panel[data-pos="active"] .wheel-desc`,
   and because a class on the drum sits above roughly a thousand nodes, each spin
   forced a style recalculation of all of them -- 1178ms of UpdateLayoutTree
   across four spins, with 160ms single frames. Keyed this way a spin only
   recalculates the handful of elements that actually changed.

   For the same reason state is expressed with opacity rather than visibility:
   visibility is inherited, so changing it on a panel drags its whole subtree
   into the recalculation. */

.wheel-panel.is-far {
  opacity: 0;
  pointer-events: none;
}

.wheel-panel.is-active {
  opacity: 1;
  pointer-events: auto;
  overflow-y: auto;
}

.wheel-panel.is-above,
.wheel-panel.is-below {
  opacity: 0.3;
  cursor: pointer;
}

.wheel-desc,
.wheel-includes,
.wheel-steps-panel {
  opacity: 0;
  transition: opacity 220ms ease;
}

.wheel-detail-on { opacity: 1; }

.wheel-panel-inner {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 2.5rem;
  height: 100%;
}

.wheel-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 1rem;
  margin-bottom: 1.1rem;
  border-radius: 50px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--card-color);
  background: color-mix(in srgb, var(--card-color) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-color) 28%, transparent);
}

.wheel-eyebrow svg,
.wheel-eyebrow [data-lucide] { width: 1.15em; height: 1.15em; }

.wheel-title {
  font-size: 2.1rem;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin-bottom: 0.9rem;
}

.wheel-desc {
  color: var(--text-muted);
  font-size: 1.02rem;
  line-height: 1.65;
  margin-bottom: 1.6rem;
}

.wheel-includes {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

.wheel-include { display: flex; gap: 0.9rem; }

.wheel-include svg,
.wheel-include [data-lucide] {
  width: 22px;
  height: 22px;
  color: var(--card-color);
  margin-top: 2px;
}

.wheel-include h4 { font-size: 1rem; font-weight: 700; margin-bottom: 0.25rem; }
.wheel-include p { color: var(--text-muted); font-size: 0.9rem; line-height: 1.55; }

/* ---- steps ---- */

.wheel-steps-panel {
  background: rgba(8, 11, 20, 0.55);
  border: 1px solid var(--glass-border);
  border-radius: 18px;
  padding: 1.6rem 1.5rem;
  display: flex;
  flex-direction: column;
}

.wheel-steps-title {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 1.2rem;
}

.wheel-steps {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1.05rem;
}

.wheel-steps li { display: flex; gap: 0.9rem; }

.wheel-step-n {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.5px;
  color: var(--card-color);
  background: color-mix(in srgb, var(--card-color) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--card-color) 30%, transparent);
}

.wheel-steps h4 { font-size: 0.95rem; font-weight: 700; margin-bottom: 0.15rem; }
.wheel-steps p { color: var(--text-muted); font-size: 0.85rem; line-height: 1.5; }

/* ---- controls ---- */

.wheel-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 1.75rem;
}

.wheel-controls button {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--glass-bg);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--text-main);
  cursor: pointer;
  transition: transform 0.25s var(--ease-spring), border-color 0.25s ease;
}

.wheel-controls button:hover {
  transform: translateY(-2px);
  border-color: var(--primary-color);
}

.wheel-count {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 1px;
  color: var(--text-muted);
  min-width: 56px;
  text-align: center;
}

.wheel-hint {
  text-align: center;
  margin-top: 0.75rem;
  font-size: 0.8rem;
  color: var(--text-muted);
  opacity: 0.75;
}

/* Desktop sizing. At 700px the panel was taller than a laptop viewport once the
   navbar is taken off, so the card never fitted on screen in one go. Wider
   section and even columns give the step copy room to wrap less, which is what
   lets the panel come down to 540px without its content overflowing. Scoped to
   the two-column layout so the tuned phone and tablet heights stay as they are. */
@media (min-width: 1101px) {
  .wheel-section { max-width: 1280px; }
  .wheel-layout { gap: 2.5rem; }
  .wheel-window { --ph: 540px; height: 620px; }
  .wheel-panel { padding: 2rem 2.25rem; border-radius: 22px; }
  .wheel-panel-inner { grid-template-columns: 1fr 1fr; gap: 2rem; }

  .wheel-eyebrow { padding: 0.38rem 0.85rem; margin-bottom: 0.85rem; font-size: 0.68rem; }
  .wheel-title { font-size: 1.75rem; margin-bottom: 0.7rem; }
  .wheel-desc { font-size: 0.95rem; line-height: 1.6; margin-bottom: 1.15rem; }
  .wheel-includes { gap: 0.85rem; }
  .wheel-include svg,
  .wheel-include [data-lucide] { width: 20px; height: 20px; }
  .wheel-include h4 { font-size: 0.95rem; margin-bottom: 0.2rem; }
  .wheel-include p { font-size: 0.85rem; line-height: 1.5; }

  .wheel-steps-panel { padding: 1.25rem; border-radius: 16px; }
  .wheel-steps-title { margin-bottom: 0.9rem; }
  .wheel-steps { gap: 0.75rem; }
  .wheel-steps li { gap: 0.75rem; }
  .wheel-step-n { width: 28px; height: 28px; border-radius: 8px; font-size: 0.68rem; }
  .wheel-steps h4 { font-size: 0.9rem; }
  .wheel-steps p { font-size: 0.82rem; line-height: 1.45; }

  .wheel-controls { margin-top: 1rem; }
  .wheel-controls button { width: 40px; height: 40px; }
  .wheel-hint { margin-top: 0.5rem; }
}

/* Just above the one-column switch the columns are narrow enough that the step
   copy wraps a line further, so the panel gets that height back. */
@media (min-width: 1101px) and (max-width: 1300px) {
  .wheel-window { --ph: 580px; height: 660px; }
}

/* Two columns stop earning their keep well before 980px: by ~1000px each one is
   about 440px wide, the copy wraps hard, and the panel needed 931px of height --
   more than it had. Switching to one column here keeps every desktop panel
   inside its box, so none of them is ever a scroll container. */
@media (max-width: 1100px) {
  .wheel-window { --ph: 790px; height: 930px; }
}

@media (max-width: 1100px) {
  .wheel-layout { grid-template-columns: 1fr; gap: 1.5rem; }
  .wheel-rail {
    flex-direction: row;
    overflow-x: auto;
    gap: 0.5rem;
    padding-bottom: 0.5rem;
    scrollbar-width: none;
  }
  .wheel-rail::-webkit-scrollbar { display: none; }
  .wheel-rail-heading { display: none; }
  .wheel-rail button {
    width: auto;
    white-space: nowrap;
    border-left: 0;
    border: 1px solid rgba(255, 255, 255, 0.09);
    border-radius: 50px;
    padding: 0.5rem 0.95rem;
    font-size: 0.85rem;
  }
  .wheel-rail button.is-active { border-color: var(--card-color, var(--primary-color)); }
  .wheel-panel-inner { grid-template-columns: 1fr; gap: 1.5rem; }
  .wheel-window { --ph: 790px; height: 930px; }
  /* On a phone one column still needs about 1000px to lay out flat, which is
     taller than the handset. Tighten the type; what is left over scrolls inside
     the panel and then chains on to the page. */
  .wheel-desc { font-size: 0.95rem; margin-bottom: 1.2rem; }
  .wheel-includes { gap: 0.85rem; }
  .wheel-steps { gap: 0.8rem; }
  .wheel-steps-panel { padding: 1.2rem 1.1rem; }
  .wheel-eyebrow { margin-bottom: 0.85rem; }
  .wheel-panel { padding: 2rem 1.5rem; }
  .wheel-title { font-size: 1.65rem; }
}

@media (max-width: 800px) {
  .wheel-window { --ph: 920px; height: 1060px; }
}

/* A phone cannot show a service in a box smaller than the screen, so stop
   trying. The panel grows to fit its copy and the page scrolls through it --
   no scroller inside a scroller, and the wheel or the thumb always moves the
   page. */
@media (max-width: 600px) {
  .wheel-window { --ph: 1140px; height: 1280px; }
}

/* iPhone SE and similar: the copy needs another 120px down here. */
@media (max-width: 340px) {
  .wheel-window { --ph: 1300px; height: 1440px; }
}

/* The spin is decoration; the content is not. Drop the rotation and let the
   panels swap in place. */
@media (prefers-reduced-motion: reduce) {
  .wheel-drum,
  .wheel-panel { transition: none; }
  .wheel-controls button:hover { transform: none; }
}

/* ==========================================================================
   Services dial
   An actual wheel. Eight labels tile a cylinder -- item i sits at
   rotateX(i * 45deg) translateZ(R), with R = (itemHeight / 2) / tan(22.5deg),
   the radius at which eight faces of that height meet edge to edge -- and the
   ring counter-rotates to bring one to the front.

   This is the shared-3D-scene construction that was too expensive for the
   content panels, and it is fine here for one reason: cost tracks the area
   being re-rasterised, and these are 46px label strips rather than 700px pages
   of body copy.
   ========================================================================== */

.wheel-dial {
  /* A grid item defaults to min-width:auto, so it grows to its content. The
     scrolling chip row now sits one level inside this element rather than being
     the grid item itself, and without this the eight chips widened the column --
     and with it the whole phone viewport -- to 1385px. */
  min-width: 0;
  --ih: 46px;
  /* (ih / 2) / tan(22.5deg) */
  --dr: calc(var(--ih) * 1.2071);
}

.wheel-dial-window {
  position: relative;
  height: calc(var(--ih) * 5);
  perspective: 700px;
  /* clip, not hidden: hidden would make this a scroll container, and the page
     scroll would die inside it. Same trap as the panels. */
  overflow: hidden;
  overflow: clip;
}

/* The selected slot, so it reads as a wheel with a window rather than a list. */
.wheel-dial-marker {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(50% - var(--ih) / 2);
  height: var(--ih);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-left: 2px solid var(--dial-color, var(--primary-color));
  transition: border-color 0.3s ease;
  pointer-events: none;
}

/* Just a box. The ring used to be the cylinder -- preserve-3d, counter-rotated,
   with the labels placed around it -- and it cost what the content panels cost
   before they were rebuilt: 2262ms of style recalculation over seven steps and
   45% of frames missed at 4x CPU, because Chromium will not composite the
   rotation of a 3D scene. Each label now carries its own perspective() and is
   placed on the cylinder by wheel.js, which is an ordinary composited
   transform. */
.wheel-dial-ring {
  position: absolute;
  inset: 0;
}

.wheel-dial-item {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(50% - var(--ih) / 2);
  height: var(--ih);
  /* transform is written by wheel.js */
  backface-visibility: hidden;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0 0.9rem;
  background: none;
  border: 0;
  color: var(--text-muted);
  font: inherit;
  font-size: 0.92rem;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  opacity: 0;
  transition: transform 380ms var(--ease-spring), opacity 0.3s ease, color 0.3s ease;
}

/* Only the front label and its two neighbours take the pointer; the rest are
   edge-on or facing away, and were intercepting clicks aimed at what you could
   actually see. */
.wheel-dial-item { pointer-events: none; }
.wheel-dial-item.is-active,
.wheel-dial-item.is-near { pointer-events: auto; }

.wheel-dial-window { cursor: grab; }
.wheel-dial-window:active { cursor: grabbing; }

.wheel-dial-item.is-near { opacity: 0.4; }
.wheel-dial-item.is-near:hover { color: var(--text-main); opacity: 0.75; }
/* Parked out of sight at the bottom of the wheel. No transition, so bringing
   one back does not animate it across the face. */
.wheel-dial-item.is-off {
  transform: perspective(700px) translate3d(0, 52px, -22px) rotateX(-88deg);
  transition: none;
  opacity: 0;
  /* Not just transparent -- unpainted. Five transparent 3D-transformed labels
     still went through the compositor on every step. */
  visibility: hidden;
}

.wheel-dial-item.is-instant { transition: none; }

.wheel-dial-item.is-active {
  color: var(--text-main);
  font-weight: 600;
  opacity: 1;
}

.wheel-dial-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.5;
  flex-shrink: 0;
  transition: background 0.3s ease, transform 0.3s ease;
}

.wheel-dial-item.is-active .wheel-dial-dot {
  background: var(--card-color);
  opacity: 1;
  transform: scale(1.35);
}

/* Below the two-column breakpoint the dial flattens into a row of chips: a
   46px-tall cylinder is not worth the vertical space on a phone. */
@media (max-width: 1100px) {
  .wheel-dial-window {
    height: auto;
    perspective: none;
    overflow: visible;
  }
  .wheel-dial-marker { display: none; }
  .wheel-dial-ring {
    position: static;
    transform: none !important;
    transform-style: flat;
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding-bottom: 0.5rem;
    scrollbar-width: none;
  }
  .wheel-dial-ring::-webkit-scrollbar { display: none; }
  .wheel-dial-item {
    position: static;
    top: auto;
    height: auto;
    transform: none !important;
    opacity: 1 !important;
    transition: none;
    width: auto;
    border: 1px solid rgba(255, 255, 255, 0.09);
    border-radius: 50px;
    padding: 0.5rem 0.95rem;
    font-size: 0.85rem;
  }
  .wheel-dial-item, .wheel-dial-item.is-near { pointer-events: auto; }
  .wheel-dial-item.is-active { border-color: var(--card-color); }
}

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

/* Honeypot: off-screen rather than display:none, because some bots skip
   fields that are explicitly hidden. Real users never reach it -- it is
   aria-hidden and out of the tab order. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
