:root {
  --dark: #1a1a1a;
  --off-white: #f7f7f7;
  --ultra-dark: #141414;
  --white: #fff;
  --line-dark: #0000001a;
  --blue: #05f;
  --line-light: #fff3;
}

.w-layout-blockcontainer {
  max-width: 940px;
  margin-left: auto;
  margin-right: auto;
  display: block;
}

.w-layout-grid {
  grid-row-gap: 16px;
  grid-column-gap: 16px;
  grid-template-rows: auto auto;
  grid-template-columns: 1fr 1fr;
  grid-auto-columns: 1fr;
  display: grid;
}

@media screen and (max-width: 991px) {
  .w-layout-blockcontainer {
    max-width: 728px;
  }
}

@media screen and (max-width: 767px) {
  .w-layout-blockcontainer {
    max-width: none;
  }
}

html {
  background-color: #141414;
}

body {
  color: #000;
  background-color: #f7f7f7;
  font-family: Geist, sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: 150%;
}

h1,
h2 {
  margin-top: 0;
  margin-bottom: 16px;
  font-size: 38px;
  font-weight: 700;
  line-height: 100%;
}

h3 {
  margin-top: 0;
  margin-bottom: 24px;
  font-size: 24px;
  font-weight: 700;
  line-height: 120%;
}

h4 {
  margin-top: 0;
  margin-bottom: 8px;
  font-size: 18px;
  font-weight: 600;
  line-height: 24px;
}

.section.hero {
  background-color: #141414;
  min-height: 75vh;
  color: var(--off-white);
  justify-content: space-between;
  display: flex;
  position: relative;
}

.section.vision-models {
  background-color: var(--dark);
  color: var(--off-white);
}

.section.cad {
  background-color: var(--ultra-dark);
  color: var(--off-white);
}

.section.cad-element {
  background-color: var(--ultra-dark);
  min-height: 100vh;
  color: var(--off-white);
}

.section.about {
  background-color: var(--white);
}

.section.footer {
  background-color: #141414;
  color: var(--off-white);
}

.section.contact {
  border-top: 1px solid var(--line-dark);
}

.sidebar-column {
  width: 25%;
  color: var(--off-white);
  flex-flow: column;
  position: fixed;
  inset: 0% 0% 0% auto;
  box-shadow: -.5px 0 0 .5px #00000026;
}

.sidebar-wrapper {
  flex-flow: column;
  justify-content: flex-end;
  width: 100%;
  height: 100%;
  display: flex;
  position: sticky;
  top: 0;
}

.hero-content-wrapper {
  flex-flow: column;
  justify-content: flex-end;
  align-items: flex-start;
  width: 80%;
  display: flex;
  position: relative;
}

.sidebar-block {
  width: 100%;
  padding: 32px;
  position: relative;
}

.sidebar-block.brand {
  background-color: var(--blue);
  justify-content: flex-end;
  align-items: center;
  height: auto;
}

/* ---- mobile hamburger toggle: hidden on desktop, shown ≤991px ---- */
.mobile-nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 28px;
  height: 20px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

.mobile-nav-toggle span {
  display: block;
  width: 100%;
  height: 2px;
  background: var(--off-white);
  border-radius: 1px;
  transition: transform .25s ease, opacity .25s ease;
}

.sidebar-block.about {
  background-color: var(--blue);
  justify-content: flex-start;
  align-items: flex-end;
  height: 100%;
  padding-top: 15%;
  display: flex;
}

/* Desktop: .sidebar-block.about used to be a direct flex child of
   .sidebar-wrapper, and its height:100% acted as a flex-shrink spacer
   that absorbed the column's leftover space, pushing the nav links to
   the bottom. Now that it (and the nav links) live inside
   .sidebar-menu-panel for the mobile accordion, that spacer role moves
   here instead - flex:1 fills the leftover space, justify-content
   pushes the about+links group to the bottom within it. See the ≤991px
   override below, which resets this back to plain block stacking so the
   accordion's height animation isn't fighting flex layout. */
.sidebar-menu-panel {
  display: flex;
  flex-flow: column;
  justify-content: flex-end;
  flex: 1;
  min-height: 0;
}

.sidebar-block.nav {
  border-top: 1px solid var(--line-dark);
  background-color: var(--off-white);
  color: var(--dark);
  text-decoration: none;
  display: flex;
}

.sidebar-nav-count {
  opacity: .45;
  margin-right: 24px;
}

/* Sidebar nav label sweep-highlight animation */
.sidebar-nav-label.sweep {
  position: relative;
  display: inline-block;
  isolation: isolate;
}

.sweep-base {
  position: relative;
  z-index: 0;
  color: var(--dark);
}

.sweep-bar {
  position: absolute;
  left: -6px;
  right: -6px;
  top: -3px;
  bottom: -3px;
  z-index: 1;
  background-color: var(--blue);
  clip-path: inset(0 100% 0 0%);
  pointer-events: none;
}

.sweep-overlay-white,
.sweep-overlay-blue {
  position: absolute;
  inset: 0;
  z-index: 2;
  white-space: nowrap;
  clip-path: inset(0 100% 0 0%);
  pointer-events: none;
}

.sweep-overlay-white {
  color: #fff;
}

.sweep-overlay-blue {
  color: var(--blue);
}

/* Phase 1 (0-50%): draws in from the left, left edge pinned at 0.
   Phase 2 (50-100%): trailing edge sweeps out to the right, exiting the box. */
.sweep.is-active .sweep-bar,
.sweep.is-active .sweep-overlay-white {
  animation: sweepPen 1.1s cubic-bezier(.65, 0, .35, 1) forwards;
}

.sweep.is-active .sweep-overlay-blue {
  animation: sweepInk 1.1s cubic-bezier(.65, 0, .35, 1) forwards;
}

.sweep.is-done .sweep-bar,
.sweep.is-done .sweep-overlay-white {
  clip-path: inset(0 0 0 100%);
}

.sweep.is-done .sweep-overlay-blue {
  clip-path: inset(0 0 0 0%);
}

@keyframes sweepPen {
  0%   { clip-path: inset(0 100% 0 0%); }
  50%  { clip-path: inset(0 0%   0 0%); }
  100% { clip-path: inset(0 0%   0 100%); }
}

@keyframes sweepInk {
  0%   { clip-path: inset(0 100% 0 0%); }
  50%  { clip-path: inset(0 100% 0 0%); }
  100% { clip-path: inset(0 0%   0 0%); }
}

.h1-hero {
  text-transform: uppercase;
  margin-bottom: 64px;
  font-size: 90px;
}

.body-copy {
  font-size: 18px;
  line-height: 150%;
}

.hero-sub-copy {
  width: 30ch;
  font-size: 18px;
}

.hero-content-block {
  padding-top: 128px;
  padding-bottom: 64px;
}

.hero-img-block {
  background-color: #012bdd;
  min-height: 50vh;
  position: relative;
  overflow: hidden;
}

/* Clean source video - never painted, only sampled as a WebGL texture. */
.hero-img-video {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Dithered output. Taller than the block so the parallax offset can slide it. */
.hero-img-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  display: block;
  will-change: top;
}

.container {
  max-width: 100%;
  padding: 128px 64px;
}

.container.footer {
  padding-top: 64px;
  padding-bottom: 64px;
}

.container.hero {
  flex-flow: column;
  justify-content: flex-end;
  align-items: flex-start;
  padding-bottom: 32px;
  display: flex;
}

.container.cad {
  padding-bottom: 32px;
}

.container.mi-full {
  padding: 0;
}

.h1 {
  margin-top: 0;
  font-size: 60px;
  font-weight: 400;
}

.h1.weigh-normal {
  font-weight: 400;
}

.h3 {
  font-size: 30px;
  font-weight: 400;
}

.h3.weight-medium {
  font-weight: 500;
}

.h3.hero {
  width: 75%;
  margin-bottom: 0;
}

.grid-block.img {
  aspect-ratio: 2 / 3;
  color: var(--off-white);
  position: relative;
}

/* Vision AI card: map thumbnail + video stacked 50/50, filling the same
   total height .grid-block.img already reserves (aspect-ratio:2/3) -
   nothing else in the grid shifts. */
.tech-media-stack {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.tech-media-stack .grid-img-block {
  flex: none;
  width: 100%;
  height: 50%;
}

.tech-media-video {
  flex: none;
  width: 100%;
  height: 50%;
  display: block;
  object-fit: cover;
  background-color: #141414;
}

.grid-block.blog {
  aspect-ratio: 2;
  color: var(--off-white);
  position: relative;
}

.btn {
  background-color: var(--blue);
  text-align: center;
  border-radius: 100px;
  padding: 16px 40px;
}

.btn.dashboard {
  margin-top: 32px;
}

.btn.case-study {
  margin-top: 32px;
  padding: 8px 32px;
  font-size: 13px;
}

.section-coumn {
  width: 75%;
}

.column-wrapper {
  display: flex;
}

.body-paragraph {
  opacity: .75;
}

.body-paragraph.partners {
  font-size: 20px;
  font-weight: 300;
  line-height: 150%;
}

.grid-data-set {
  grid-column-gap: 64px;
  grid-row-gap: 64px;
  margin-top: 128px;
}

.list {
  padding-left: 16px;
}

.list-item {
  padding-top: 8px;
  padding-bottom: 8px;
}

.list-label {
  margin-bottom: 0;
}

/* Base box only. Every instance supplies its own background-image via a
   modifier (.case-study / .map-vision / .map-infra / .map-rti), so no
   placeholder image is declared here. */
.grid-img-block {
  background-position: 0 0, 0 0;
  background-repeat: repeat, no-repeat;
  background-size: auto, cover;
  width: 100%;
  height: 100%;
}

.grid-img-block.case-study {
  background-image: linear-gradient(#00000040, #00000040), url('../images/image-okada-closeup-dithered.png');
  background-position: 0 0, center;
  background-repeat: repeat, no-repeat;
  background-size: auto, cover;
}

.grid-img-block.map-vision {
  background-image: url('../maps/tamale-plane-roads.svg');
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  background-color: #1a1a1a;
  border: 1px solid rgba(255, 255, 255, .07);
}

.grid-img-block.map-infra {
  background-image: url('../maps/tamale-plane-infra.svg');
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  background-color: #1a1a1a;
  border: 1px solid rgba(255, 255, 255, .07);
}

.grid-img-block.map-rti {
  background-image: url('../maps/tamale-plane-rti.svg');
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  background-color: #1a1a1a;
  border: 1px solid rgba(255, 255, 255, .07);
}

.data-set-labels {
  letter-spacing: 2px;
  margin-bottom: 16px;
  font-family: Geist Mono, sans-serif;
  font-size: 12px;
  font-weight: 400;
}

.data-set-labels.partners {
  margin-bottom: 32px;
}

.data-set-wrapper {
  padding: 16px;
}

.h4 {
  /* var(--blue) (#0055ff) on this section's #1a1a1a background is only
     ~3.1:1 contrast, below WCAG AA's 4.5:1 for normal-weight text this
     size. This tint keeps the same hue but lightens it enough to clear
     AA (~4.8:1) without touching --blue itself, which is used elsewhere
     for buttons/fills where the original value is fine. */
  color: #4080ff;
  font-weight: 500;
}

.h4.white {
  color: var(--off-white);
}

.content-block {
  margin-bottom: 32px;
}

.content-block._50p {
  padding-right: 50%;
}

.content-block.bm-128 {
  margin-bottom: 128px;
}

.grid {
  grid-template-rows: auto;
}

.cad-block {
  margin-bottom: 32px;
}

.cad-block._50p {
  padding-right: 50%;
}

.grid-cad {
  grid-column-gap: 64px;
  grid-row-gap: 64px;
  grid-template-rows: auto;
  margin-top: 64px;
}

.grid-partners {
  grid-column-gap: 64px;
  grid-row-gap: 64px;
}

.partner-block {
  aspect-ratio: 1;
  background-color: #eef1f4;
  flex-flow: column;
  justify-content: center;
  align-items: flex-start;
  padding: 32px 15%;
  display: flex;
  min-width: 0;
}

.partner-block.img {
  color: var(--off-white);
  position: relative;
}

.grid-blog {
  grid-column-gap: 64px;
  grid-row-gap: 64px;
}

.grid-contact {
  grid-column-gap: 64px;
  grid-row-gap: 64px;
  grid-template-rows: auto;
}

.grid-contact-block {
  width: 100%;
  padding-top: 32px;
  padding-bottom: 32px;
  padding-right: 32px;
  display: flex;
  position: relative;
}

.contact-link {
  color: inherit;
  text-decoration: none;
}

.contact-link:hover {
  text-decoration: underline;
}

.grid-contact-block.brand {
  justify-content: flex-end;
  align-items: center;
  height: auto;
}

.grid-contact-block.about {
  justify-content: flex-start;
  align-items: flex-end;
  height: 100%;
  padding-top: 15%;
  display: flex;
}

.grid-contact-block.nav {
  border-top: 1px solid var(--line-dark);
  background-color: var(--off-white);
  color: #000;
  display: flex;
}

.grid-form {
  grid-column-gap: 64px;
  grid-row-gap: 64px;
  margin-top: 32px;
  margin-bottom: 32px;
}

.invitation-form-block {
  margin-top: 64px;
  margin-bottom: 64px;
}

.success-message {
  background-color: #fff0;
}

.error-message {
  color: #f20;
  background-color: #fff0;
  padding-left: 0;
  padding-right: 0;
}

.btn-2 {
  grid-column-gap: 8px;
  grid-row-gap: 8px;
  text-align: center;
  background-color: #2c2723;
  border-radius: 200px;
  justify-content: center;
  align-items: center;
  padding: 16px 64px;
  text-decoration: none;
}

.btn-2.secondary {
  color: #000;
  background-color: #fff;
}

.text-field {
  border-style: none none solid;
  border-width: 1px;
  border-color: black black var(--line-dark);
  color: #fff;
  background-color: #fff0;
  min-height: 54px;
  margin-bottom: 0;
  padding-left: 0;
  padding-right: 0;
}

.text-field:hover, .text-field:focus {
  border-bottom-color: var(--blue);
}

.text-field.area {
  min-height: 154px;
}

.form-label {
  font-weight: 500;
}

.grid-footer {
  grid-column-gap: 64px;
  grid-row-gap: 64px;
  grid-template-rows: auto;
  grid-template-columns: 1fr 1fr 1fr;
}

.deployment-wrapper {
  grid-column-gap: 16px;
  grid-row-gap: 16px;
  flex-flow: column;
  margin-top: 32px;
  display: flex;
}

.footer-link {
  border-bottom: 1px solid var(--line-light);
  width: 100%;
  padding-top: 16px;
  padding-bottom: 16px;
  padding-right: 32px;
  display: flex;
  position: relative;
}

a.footer-link {
  color: inherit;
  text-decoration: none;
}

a.footer-link:hover .sidebar-nav-label {
  text-decoration: underline;
}

.footer-link.brand {
  justify-content: flex-end;
  align-items: center;
  height: auto;
}

.footer-link.about {
  justify-content: flex-start;
  align-items: flex-end;
  height: 100%;
  padding-top: 15%;
  display: flex;
}

.footer-link.nav {
  border-top: 1px solid var(--line-dark);
  background-color: var(--off-white);
  color: #000;
  display: flex;
}

.keep-scrolling-bar {
  background-color: var(--blue);
  width: 60%;
  height: 30px;
}

.case-study-wrapper {
  margin-top: 128px;
}

@media screen and (max-width: 991px) {
  .sidebar-column {
    width: 100%;
    height: auto;
    position: relative;
  }

  /* Desktop's flex column + height:100% + sticky (for pinning content to
     the bottom of a full-height column) fights the accordion here: with
     .sidebar-column now height:auto, this 100% resolves against an
     ill-defined height and the flex context shrinks the panel regardless
     of its own explicit height. Plain block flow lets it size correctly. */
  .sidebar-wrapper {
    display: block;
    height: auto;
    position: static;
  }

  /* collapse the sidebar into a hamburger menu: brand bar stays visible,
     the tagline + nav links are hidden until toggled open */
  .sidebar-block.brand {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-top: 20px;
    padding-bottom: 20px;
  }

  .mobile-nav-toggle {
    display: flex;
  }

  /* accordion: height animates 0 → content height (and back), so the
     panel pushes the page below it open/closed instead of snapping.
     Reset the desktop flex-spacer role (see base rule) back to plain
     block stacking - flex + justify-content:flex-end would otherwise
     fight the height animation (content would reveal bottom-up instead
     of collapsing/growing from the top). */
  .sidebar-menu-panel {
    display: block;
    flex: none;
    height: 0;
    overflow: hidden;
    transition: height .35s cubic-bezier(.4, 0, .2, 1);
  }

  /* During the open transition the panel briefly holds an explicit pixel
     height (see the JS); about's desktop height:100% would then blow up
     to that whole box in block flow and clip the nav links below it
     until the transition settles. Keep it at its natural content height
     on mobile instead. */
  .sidebar-block.about {
    height: auto;
  }

  .sidebar-column.is-menu-open .mobile-nav-toggle span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }

  .sidebar-column.is-menu-open .mobile-nav-toggle span:nth-child(2) {
    opacity: 0;
  }

  .sidebar-column.is-menu-open .mobile-nav-toggle span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }

  .hero-content-wrapper {
    width: 100%;
  }

  .hero-sub-copy {
    width: auto;
  }

  .container {
    padding-left: 32px;
    padding-right: 32px;
  }

  .container.hero {
    padding-bottom: 64px;
  }

  .section-coumn {
    width: 100%;
  }

  .column-wrapper {
    flex-flow: column-reverse wrap-reverse;
  }

  .grid-data-set {
    grid-column-gap: 32px;
    grid-row-gap: 32px;
  }

  .grid {
    grid-template-columns: 1fr;
  }

  .grid-cad {
    grid-column-gap: 32px;
    grid-row-gap: 32px;
  }

  .grid-partners {
    grid-column-gap: 16px;
    grid-row-gap: 16px;
  }

  .grid-contact {
    grid-template-columns: 1fr;
  }

  .grid-footer {
    grid-template-columns: 1fr 1fr;
  }
}

@media screen and (max-width: 767px) {
  .hero-content-wrapper {
    width: 100%;
  }

  .container {
    padding-top: 64px;
    padding-bottom: 64px;
  }

  .h1 {
    font-size: 40px;
  }

  .h1-hero {
    font-size: 48px;
    margin-bottom: 32px;
  }

  .h3.hero {
    width: 100%;
    font-size: 20px;
  }

  .grid-block.img {
    aspect-ratio: 1;
  }

  .grid-data-set {
    grid-template-columns: 1fr;
  }

  /* Mobile-only reorder: Vision AI and RTI already stack heading+copy,
     then the map/video card, then the list - Infrastructure is the odd
     one out (card comes first in the DOM), so just it needs an explicit
     order here to match. Desktop keeps its original DOM order/layout. */
  .infra-text-block {
    order: 1;
  }

  #w-node-_256344c0-146f-2130-dd26-0937216b4635-1e9204e4 {
    order: 2;
  }

  #w-node-_256344c0-146f-2130-dd26-0937216b463c-1e9204e4 {
    order: 3;
  }

  .grid-partners {
    grid-template-rows: auto;
    grid-template-columns: 1fr;
  }
}

@media screen and (max-width: 479px) {
  .container {
    padding-left: 16px;
    padding-right: 16px;
  }

  .h1-hero {
    font-size: 38px;
  }

  .h3.hero {
    font-size: 18px;
  }

  .btn {
    width: 100%;
  }

  .btn.case-study {
    width: auto;
    margin-top: 16px;
  }

  .grid-data-set {
    margin-top: 64px;
  }

  .grid-cad {
    grid-template-columns: 1fr;
  }

  .partner-block {
    padding-left: 5%;
    padding-right: 5%;
  }

  .grid-blog {
    grid-template-rows: auto;
    grid-template-columns: 1fr;
  }

  .grid-contact, .grid-form {
    grid-template-columns: 1fr;
  }

  .btn-2 {
    width: 100%;
  }

  .grid-footer {
    grid-template-columns: 1fr;
  }
}

#w-node-a7a526cf-3618-054e-3acd-6efe7ab147a3-1e9204e4 {
  grid-area: span 2 / span 1 / span 2 / span 1;
}

#w-node-aeea5cd5-151d-021b-aea0-7a3741970aca-1e9204e4 {
  align-self: end;
}

#w-node-_256344c0-146f-2130-dd26-0937216b4635-1e9204e4 {
  grid-area: span 2 / span 1 / span 2 / span 1;
}

#w-node-_256344c0-146f-2130-dd26-0937216b463c-1e9204e4 {
  align-self: end;
}

#w-node-_8e7a1f65-1c85-8791-e0f1-d38246a8f9ef-1e9204e4 {
  grid-area: span 2 / span 1 / span 2 / span 1;
}

#w-node-_564d9e7e-44c1-934d-40f5-f8ecbc195265-1e9204e4 {
  align-self: end;
}

#w-node-a3c3ebd9-9deb-9202-21db-8cf504c3adff-1e9204e4 {
  grid-area: span 2 / span 1 / span 2 / span 1;
}

#w-node-ea3c8504-e23a-528d-5723-a5846fbfd6ac-1e9204e4, #w-node-_3ec76e73-adc4-74d7-75b2-916e70adb672-1e9204e4 {
  grid-area: span 1 / span 2 / span 1 / span 2;
}

@media screen and (max-width: 479px) {
  #w-node-_1d7cdb57-cae9-7a42-53bd-f7d0fa90ba83-1e9204e4, #w-node-ea3c8504-e23a-528d-5723-a5846fbfd6ac-1e9204e4, #w-node-_3ec76e73-adc4-74d7-75b2-916e70adb672-1e9204e4 {
    grid-area: span 1 / span 1 / span 1 / span 1;
  }
}


