/* ============================================================
   Ahmad Brothers — Accounts Software Developers
   ============================================================ */

:root {
  --bg: #0b1020;
  --surface: #121a30;
  --surface-2: #16203a;
  --line: rgba(255, 255, 255, 0.08);
  --text: #e8ecf6;
  --muted: #9aa6c2;
  --brand: #4f8cff;
  --brand-2: #22d3ee;
  --accent: #f5b544;
  --radius: 16px;
  --max: 1140px;
  --shadow: 0 18px 40px rgba(0, 0, 0, 0.35);

  /* ---- "Head" theme: the HERO flips dark <-> light when a hero
         button is hovered. The nav bar is deliberately excluded and
         stays solid black. ---- */
  --head-bg: #0b1020;
  /* hero base */
  --head-text: #e8ecf6;
  --head-muted: #9aa6c2;
  --head-line: rgba(255, 255, 255, 0.10);
  --head-chip-fg: #22d3ee;
  --head-chip-bg: rgba(34, 211, 238, 0.10);
  --head-chip-line: rgba(34, 211, 238, 0.28);
  --head-ghost-bg: rgba(255, 255, 255, 0.05);
  --head-ghost-line: rgba(255, 255, 255, 0.12);
  --head-speed: 0.5s;
  /* the code fades out when the hero turns light, so pale code never
     sits on a pale background */
  --head-code-opacity: 1;

  /* Nav bar: fixed, never themed. */
  --nav-bg: #000000;
  --nav-line: rgba(255, 255, 255, 0.14);
  --nav-text: #e8ecf6;
  --nav-muted: #9aa6c2;
}

/* Light state for the hero. Defined on <body> so the hero, its
   code canvas and its glow layer all flip together.
   :focus-visible is included so keyboard users get the same effect.
   The nav bar is intentionally not in this list. */
body:has(.hero .btn:hover),
body:has(.hero .btn:focus-visible) {
  --head-bg: #eef2fa;
  --head-text: #0a0f1e;
  --head-muted: #4c5878;
  --head-line: rgba(10, 15, 30, 0.14);
  --head-chip-fg: #06798e;
  --head-chip-bg: rgba(6, 121, 142, 0.10);
  --head-chip-line: rgba(6, 121, 142, 0.30);
  --head-ghost-bg: rgba(10, 15, 30, 0.05);
  --head-ghost-line: rgba(10, 15, 30, 0.16);
  --head-code-opacity: 0.10;   /* pale code on a pale background */
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

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

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

h1,
h2,
h3,
h4 {
  line-height: 1.2;
  margin: 0 0 0.5em;
  letter-spacing: -0.02em;
}

h1 {
  font-size: clamp(2.1rem, 5vw, 3.4rem);
  font-weight: 800;
}

h2 {
  font-size: clamp(1.7rem, 3.5vw, 2.4rem);
  font-weight: 800;
}

h3 {
  font-size: 1.15rem;
  font-weight: 700;
}

h4 {
  font-size: 0.95rem;
  font-weight: 700;
}

p {
  margin: 0 0 1em;
  color: var(--muted);
}

.container {
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 22px;
}

/* ============================================================
   ANIMATED CODE BACKGROUND
   ============================================================ */
.code-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  display: block;
  /* soft vertical fade so the code dissolves at the edges */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 22%, #000 68%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 22%, #000 68%, transparent 100%);
}

/* the hero's code fades with the theme flip */
.hero .code-bg {
  opacity: var(--head-code-opacity);
  transition: opacity var(--head-speed) ease;
}

/* keep the readable content above decorative layers */
.header-inner,
.hero-inner {
  position: relative;
  z-index: 1;
}

/* ---------- Buttons ---------- */
.btn {
  position: relative;
  display: inline-block;
  padding: 13px 24px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.95rem;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow 0.25s ease,
    background 0.25s ease,
    color 0.25s ease,
    border-color 0.25s ease;
}

.btn:hover {
  transform: translateY(-3px);
}

.btn:active {
  transform: translateY(-1px);
}

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

/* --- Primary: lights up and glows on hover --- */
.btn-primary {
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  color: #06101f;
  box-shadow: 0 10px 24px rgba(79, 140, 255, 0.32);
}

.btn-primary:hover {
  background: linear-gradient(135deg, #7aa8ff, #5ceaff);
  color: #030b18;
  box-shadow:
    0 0 0 5px rgba(79, 140, 255, 0.20),
    0 0 24px rgba(34, 211, 238, 0.55),
    0 14px 34px rgba(79, 140, 255, 0.45);
}

/* --- Ghost: fills with a light on hover --- */
.btn-ghost {
  border-color: var(--head-ghost-line);
  background: var(--head-ghost-bg);
  color: var(--head-text);
}

.btn-ghost:hover {
  /* solid brand fill so the white label stays readable on the
     light background the hover creates */
  background: linear-gradient(135deg, #2f6fe0, #1198b5);
  border-color: #0d7f9b;
  color: #ffffff;
  box-shadow:
    0 0 0 5px rgba(34, 211, 238, 0.15),
    0 0 26px rgba(34, 211, 238, 0.40),
    0 12px 30px rgba(30, 80, 180, 0.35);
}

/* ============================================================
   HEAD-SECTION BUTTONS: ANIMATED GRADIENT ON HOVER
   The tile is twice the button's width, so travelling 0% -> 100%
   shifts it by exactly one button width — half a tile. For that to
   loop, the gradient itself must repeat every half tile, which is
   why each one is written out as two full cycles (5 stops) with the
   first and last stop matching. Animating to 200% instead would
   swing the tile clear off the button and flash at the wrap.
   `background` is dropped from the transition on these buttons so
   it cannot fight the running animation.
   ============================================================ */
@keyframes btn-sweep-fast {
  from {
    background-position: 0% 50%;
  }

  to {
    background-position: 100% 50%;
  }
}

.hero-actions .btn {
  transition-property: transform, box-shadow, color, border-color;
}

/* --- primary: bright sweep; the dark label stays legible on every stop --- */
.hero-actions .btn-primary {
  background-image: linear-gradient(90deg,
      #4f8cff 0%, #22d3ee 25%, #4f8cff 50%, #22d3ee 75%, #4f8cff 100%);
  background-size: 200% 100%;
  background-position: 0% 50%;
}

.hero-actions .btn-primary:hover,
.hero-actions .btn-primary:focus-visible {
  animation: btn-sweep-fast 0.9s linear infinite;
  color: #030b18;
  box-shadow:
    0 0 0 5px rgba(79, 140, 255, 0.20),
    0 0 26px rgba(34, 211, 238, 0.55),
    0 14px 34px rgba(79, 140, 255, 0.45);
}

/* --- ghost: a deeper sweep, because its label is white --- */
.hero-actions .btn-ghost {
  background-image: linear-gradient(90deg,
      #1d4ed8 0%, #0e7490 25%, #1d4ed8 50%, #0e7490 75%, #1d4ed8 100%);
  background-size: 200% 100%;
  background-position: 0% 50%;
}

.hero-actions .btn-ghost:hover,
.hero-actions .btn-ghost:focus-visible {
  animation: btn-sweep-fast 0.75s linear infinite;
  color: #ffffff;
  border-color: #4c1d95;
  box-shadow:
    0 0 0 5px rgba(34, 211, 238, 0.15),
    0 0 26px rgba(34, 211, 238, 0.40),
    0 12px 30px rgba(30, 80, 180, 0.35);
}

/* the sweep is decoration, so it stands down for reduced motion */
@media (prefers-reduced-motion: reduce) {

  .hero-actions .btn-primary:hover,
  .hero-actions .btn-primary:focus-visible,
  .hero-actions .btn-ghost:hover,
  .hero-actions .btn-ghost:focus-visible {
    animation: none;
  }

  /* the code rain stands down entirely; script.js paints one static
     frame instead, so the hero is never left blank */
  .hero .code-bg { display: none; }
}

.eyebrow {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-2);
  background: rgba(34, 211, 238, 0.1);
  border: 1px solid rgba(34, 211, 238, 0.25);
  padding: 5px 12px;
  border-radius: 999px;
  margin-bottom: 18px;
}

/* ============================================================
   HEADER
   ============================================================ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  /* Permanently black. The nav bar never lights up, so its colours
     come from the fixed --nav-* vars, never from --head-*. */
  background-color: var(--nav-bg);
  border-bottom: 1px solid var(--nav-line);
  /* NB: no `overflow: hidden` here — it would clip the mobile dropdown. */
}

/* ---------- Header torch ----------
   Hovering a nav link or a header button lights a torch across the
   whole header. Two stacked backgrounds do the work: a flat warm lift
   that raises the entire bar, plus a wide radial core under the
   pointer that falls off into the brand colours. The flat layer is
   what makes the *whole* background light up rather than just a
   spotlight; the radial is the bright core that reads as a flame.
   The element sits under the content (z-index 0 vs 1) and never
   intercepts clicks. --torch-x / --torch-y are the pointer position
   within the header, written by script.js. */
.header-torch {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.45s ease;
  background-image:
    /* core: hot centre under the pointer */
    radial-gradient(70% 190% at var(--torch-x, 50%) var(--torch-y, 50%),
      rgba(255, 240, 214, 0.40) 0%,
      rgba(255, 209, 138, 0.26) 26%,
      rgba(79, 140, 255, 0.17) 52%,
      rgba(34, 211, 238, 0.09) 72%,
      transparent 100%),
    /* ambient: uniform lift so the whole bar brightens, edges included */
    linear-gradient(180deg,
      rgba(255, 246, 226, 0.13) 0%,
      rgba(255, 214, 150, 0.11) 50%,
      rgba(122, 168, 255, 0.12) 100%);
}

.site-header.is-torched .header-torch {
  opacity: 1;
  /* a slow breath so it reads as a flame rather than a static wash */
  animation: torch-flicker 2.6s ease-in-out infinite;
}

@keyframes torch-flicker {

  0%,
  100% {
    opacity: 1;
  }

  38% {
    opacity: 0.9;
  }

  62% {
    opacity: 0.97;
  }
}

/* The light itself still answers the hover — only the flicker stands
   down, since it is decoration that moves on its own. */
@media (prefers-reduced-motion: reduce) {
  .site-header.is-torched .header-torch {
    animation: none;
  }
}

.header-inner {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  height: 74px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand-mark {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 12px;
  font-weight: 800;
  font-size: 0.95rem;
  color: #06101f;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  flex-shrink: 0;
}

.brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}

.brand-text strong {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--nav-text);
}

.brand-text small {
  font-size: 0.72rem;
  color: var(--nav-muted);
  letter-spacing: 0.03em;
}

.nav {
  display: flex;
  align-items: center;
  gap: 26px;
}

/* :not(.btn) keeps these link styles from overriding the
   button transition/hover rules (this selector is more specific). */
.nav>a:not(.btn) {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 6px 0;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--nav-muted);
  transition: color 0.25s ease;
}

/* ---------- Nav link icon chip ----------
   A small rounded tile behind each icon. It fills with the brand
   gradient and the glyph pops on hover/focus, alongside the existing
   underline wipe. The icon sits in its own transform so it can move
   independently of the link's colour transition. */
.nav-icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border-radius: 9px;
  color: var(--nav-muted);
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.06);
  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease,
    transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow 0.3s ease;
}

.nav-icon svg {
  display: block;
  width: 15px;
  height: 15px;
}

.nav>a:not(.btn):hover .nav-icon,
.nav>a:not(.btn):focus-visible .nav-icon {
  color: #06101f;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  border-color: transparent;
  transform: scale(1.1) translateY(-1px);
  box-shadow: 0 0 16px rgba(79, 140, 255, 0.45);
}

/* a gradient underline that wipes in from the left on hover */
.nav>a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 2px;
  border-radius: 2px;
  background-image: linear-gradient(90deg, var(--brand), var(--brand-2));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

.nav>a:not(.btn):hover {
  color: var(--nav-text);
}

.nav>a:not(.btn):hover::after,
.nav>a:not(.btn):focus-visible::after {
  transform: scaleX(1);
}

.nav>a:not(.btn):focus-visible {
  color: var(--nav-text);
  outline: none;
}

.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: 0;
  padding: 8px;
  cursor: pointer;
}

.nav-toggle span {
  width: 24px;
  height: 2px;
  background: var(--nav-text);
  border-radius: 2px;
  transition: transform 0.2s ease, 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);
}

/* ============================================================
   HERO
   ============================================================ */
.hero {
  position: relative;
  padding: clamp(60px, 9vw, 110px) 0;
  background-color: var(--head-bg);
  border-bottom: 1px solid var(--head-line);
  overflow: hidden;
  transition: background-color var(--head-speed) ease,
    border-color var(--head-speed) ease;
}

.hero h1 {
  color: var(--head-text);
  transition: color var(--head-speed) ease;
}

.hero-copy p {
  color: var(--head-muted);
  transition: color var(--head-speed) ease;
}

/* the hero's location chip follows the head theme too */
.hero .eyebrow {
  color: var(--head-chip-fg);
  background: var(--head-chip-bg);
  border-color: var(--head-chip-line);
  transition: color var(--head-speed) ease,
    background-color var(--head-speed) ease,
    border-color var(--head-speed) ease;
}

.hero-inner {
  display: flex;
  justify-content: center;
}

.hero-copy {
  max-width: 780px;
  text-align: center;
}

.hero-copy p {
  font-size: 1.08rem;
  margin-left: auto;
  margin-right: auto;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: 26px;
}

/* ============================================================
   SECTIONS
   ============================================================ */
.section {
  padding: clamp(60px, 8vw, 100px) 0;
}

.section-alt {
  position: relative;
  background: var(--surface);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.section-head {
  max-width: 640px;
  margin-bottom: 44px;
}

.section-head p {
  font-size: 1.03rem;
}

/* the team heading is centred above the carousel */
#team .section-head {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

/* this section is a tall showcase, so it runs tighter than the others */
#team.section-alt {
  padding-top: clamp(26px, 3vw, 44px);
  padding-bottom: clamp(26px, 3vw, 44px);
}

#team .section-head {
  margin-bottom: 18px;
}

.grid {
  display: grid;
  gap: 22px;
}

.grid-3 {
  grid-template-columns: repeat(3, 1fr);
}

.grid-4 {
  grid-template-columns: repeat(4, 1fr);
}

/* ============================================================
   MOVING GRADIENT BEHIND THE PRODUCTS SECTION
   A different palette, angle and tempo from the team section so the
   two never animate in step, plus the same dark scrim so the
   heading stays readable wherever the colour lands.
   ============================================================ */
@keyframes products-gradient {
  0% {
    background-position: 100% 0%;
  }

  50% {
    background-position: 0% 100%;
  }

  100% {
    background-position: 100% 0%;
  }
}

@keyframes products-aurora {
  0% {
    background-position: 0% 0%, 85% 15%, 20% 90%;
  }

  50% {
    background-position: 60% 70%, 15% 45%, 80% 10%;
  }

  100% {
    background-position: 0% 0%, 85% 15%, 20% 90%;
  }
}

#products {
  position: relative;
  background: var(--bg);
}

#products::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: linear-gradient(135deg,
      rgba(28, 52, 148, 0.46) 0%,
      rgba(12, 92, 138, 0.46) 30%,
      rgba(76, 40, 160, 0.42) 58%,
      rgba(12, 92, 138, 0.46) 80%,
      rgba(28, 52, 148, 0.46) 100%);
  background-size: 300% 300%;
  animation: products-gradient 26s ease-in-out infinite;
}

#products::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(9, 14, 30, 0.42), rgba(9, 14, 30, 0.42)),
    radial-gradient(closest-side, rgba(56, 189, 248, 0.20), transparent 72%),
    radial-gradient(closest-side, rgba(99, 102, 241, 0.20), transparent 72%),
    radial-gradient(closest-side, rgba(45, 212, 191, 0.16), transparent 72%);
  background-size: 100% 100%, 58% 70%, 52% 64%, 46% 60%;
  background-repeat: no-repeat;
  background-position: 0% 0%, 85% 15%, 20% 90%;
  animation: products-aurora 23s ease-in-out infinite;
}

#products>.container {
  position: relative;
  z-index: 1;
}

/* centred heading, matching the team and contact sections */
#products {
  padding-top: clamp(20px, 2.2vw, 34px);
  padding-bottom: clamp(20px, 2.2vw, 34px);
}

#products .section-head {
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 16px;
  text-align: center;
}

/* a slightly smaller heading keeps the whole section compact */
#products .section-head h2 {
  font-size: clamp(1.6rem, 2.6vw, 2.1rem);
}

#products .section-head p {
  color: #c5cfe6;
}

#products .eyebrow {
  color: #8df0fb;
  background: rgba(8, 16, 38, 0.62);
  border-color: rgba(141, 240, 251, 0.5);
}

/* ---------- Product cards ---------- */
/* The float animates the standalone `translate` property, not
   `transform`. A running animation would otherwise win the cascade
   and permanently override the :hover transform below; keeping them
   on separate properties lets both apply at once. */
@keyframes card-float {

  0%,
  100% {
    translate: 0 0;
  }

  50% {
    translate: 0 -13px;
  }
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  animation: card-float 7s ease-in-out infinite;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.card:hover {
  transform: translateY(-6px) scale(1.02);
  border-color: rgba(79, 140, 255, 0.5);
  box-shadow: var(--shadow);
}

/* Staggered, and each card gets its own period so the six never
   drift back into a visible repeating pattern. */
#products .card:nth-child(1) {
  animation-duration: 6.6s;
  animation-delay: 0s;
}

#products .card:nth-child(2) {
  animation-duration: 7.9s;
  animation-delay: -1.1s;
}

#products .card:nth-child(3) {
  animation-duration: 7.2s;
  animation-delay: -2.4s;
}

#products .card:nth-child(4) {
  animation-duration: 8.3s;
  animation-delay: -0.6s;
}

#products .card:nth-child(5) {
  animation-duration: 6.9s;
  animation-delay: -3.2s;
}

#products .card:nth-child(6) {
  animation-duration: 7.5s;
  animation-delay: -1.8s;
}

/* ---------- Product cards: envelope reveal ----------
   Closed: you see an envelope face carrying the product name.
   On hover the flap folds back, the face drops away and the details
   card rises out of the envelope. */
.card.envelope {
  position: relative;
  height: 240px;
  padding: 0;
  background: transparent;
  border: 0;
  overflow: hidden;
  /* clips the face as it drops away */
  perspective: 800px;
}

.card.envelope:hover,
.card.envelope:focus-visible {
  box-shadow: none;
}

.card.envelope:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 4px;
  border-radius: var(--radius);
}

/* the letter: the details card, waiting behind the envelope face.
   Its type is set tighter than the rest of the page so the card can
   stay short without the copy spilling out. */
.env-letter {
  position: absolute;
  inset: 9px;
  z-index: 2;
  padding: 15px 15px;
  border-radius: calc(var(--radius) - 4px);
  background: var(--surface-2);
  border: 1px solid var(--line);
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.35s ease, transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}

.env-letter p {
  font-size: 0.86rem;
  line-height: 1.5;
  margin-bottom: 10px;
}

.env-letter .feature-list {
  margin-top: 10px;
  gap: 6px;
}

.env-letter .feature-list li {
  font-size: 0.8rem;
  line-height: 1.4;
  padding-left: 20px;
}

/* the envelope face: product icon + name. The tall top padding keeps
   the name clear of the flap's triangular point. */
.env-front {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  /* clears the flap's point, which sits at 52% of the card height */
  padding: 132px 20px 18px;
  text-align: center;
  border-radius: var(--radius);
  background: linear-gradient(180deg, #1d2846 0%, #141d36 100%);
  border: 1px solid var(--line);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
  transform-origin: 50% 100%;
  transition: transform 0.55s cubic-bezier(0.65, 0, 0.35, 1), box-shadow 0.3s ease;
}

.env-front h3 {
  margin: 0;
}

.env-front .card-icon {
  margin-bottom: 0;
}

/* the flap: a triangle hinged along the top edge */
.env-flap {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 52%;
  z-index: 4;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  background: linear-gradient(180deg, #28375d 0%, #1b2543 100%);
  transform-origin: 50% 0;
  transform: rotateX(0deg);
  transition: transform 0.5s cubic-bezier(0.6, 0, 0.3, 1);
  pointer-events: none;
}

/* --- open --- */
.card.envelope:hover .env-flap,
.card.envelope:focus-visible .env-flap {
  transform: rotateX(-168deg);
}

.card.envelope:hover .env-front,
.card.envelope:focus-visible .env-front {
  transform: translateY(100%);
}

.card.envelope:hover .env-letter,
.card.envelope:focus-visible .env-letter {
  opacity: 1;
  transform: translateY(0);
}

.card-icon {
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  border-radius: 13px;
  font-weight: 800;
  font-size: 0.9rem;
  letter-spacing: 0.05em;
  color: #06101f;
  background: linear-gradient(135deg, var(--accent), #ff8a3d);
  margin-bottom: 18px;
}

.card p {
  font-size: 0.95rem;
}

.feature-list {
  list-style: none;
  padding: 0;
  margin: 16px 0 0;
  display: grid;
  gap: 8px;
}

.feature-list li {
  position: relative;
  padding-left: 22px;
  font-size: 0.88rem;
  color: var(--muted);
}

.feature-list li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--brand-2);
  font-weight: 700;
}

/* ---------- Team ---------- */
/* Default state is a plain responsive grid. This doubles as the
   fallback when JS is off or the user prefers reduced motion. */
.team-carousel {
  position: relative;

  /* --- orbit geometry (prefixed to avoid clashing with the
         global --radius used for border-radius) ---
     The track is a wide, short ellipse rather than a true circle:
     spreading the cards horizontally and pulling them in vertically
     cuts ~220px off the section height without letting cards collide.
     --card-h matches the real height of the compacted card below, so
     the text never spills outside the card border. */
  --card-w: 200px;
  --card-h: 195px;
  --orbit-rx: 300px;
  /* horizontal distance from the hub */
  --orbit-ry: 100px;
  /* vertical distance from the hub */
  --orbit-mid: 0.70711;
  /* sin/cos of 45deg, used for the arc midpoints */
  /* the card resting at the bottom swells, the rest stay small */
  --orbit-focus: 1.35;
  --orbit-side: 0.6;
  --orbit-back: 0.42;
  /* raises the hub so the enlarged resting card has room below it,
     while the small back card only needs a little room above */
  --orbit-lift: 42px;
  --orbit-step: 3.7s;
  /* 3s resting + 0.7s travelling */
  --orbit-cycle: 14.8s;
  /* 4 cards x --orbit-step */
}

.carousel-viewport {
  overflow: hidden;
}

.carousel-ring {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 22px;
}

.carousel-item {
  display: flex;
}

.carousel-item .person {
  flex: 1;
}

/* ---- Circular mode. The script adds .is-active only when motion is
       allowed, so the grid above survives as the no-motion fallback. ----
       Flat 2D orbit: no perspective and no ring tilt, so the card in
       focus is perfectly upright rather than leaning back. */
.team-carousel.is-active .carousel-viewport {
  height: 385px;
}

.team-carousel.is-active .carousel-ring {
  position: relative;
  display: block;
  height: 100%;
  transform: translateY(calc(var(--orbit-lift) * -1));
}

/* inset:0 + margin:auto centres each card on the hub without touching
   transform, which the orbit animation needs for itself. */
.team-carousel.is-active .carousel-item {
  position: absolute;
  inset: 0;
  margin: auto;
  width: var(--card-w);
  height: var(--card-h);
  display: block;
  animation: team-orbit var(--orbit-cycle) ease-in-out infinite;
  /* negative delay staggers each card by one step, so the ring turns
     as a unit and every card reaches the bottom in turn */
  animation-delay: calc(var(--i) * var(--orbit-step) * -1);
}

/* Compact the team card for the orbit. The bio is clamped to 3 lines so
   the card height is deterministic at every breakpoint — that is what
   keeps the copy inside the card border and lets --card-h stay small. */
.team-carousel.is-active .person {
  height: 100%;
  padding: 16px 14px;
}

.team-carousel.is-active .person .avatar {
  width: 48px;
  height: 48px;
  font-size: 0.95rem;
  margin-bottom: 10px;
}

.team-carousel.is-active .person h3 {
  font-size: 1.02rem;
  margin-bottom: 4px;
}

.team-carousel.is-active .person .role {
  font-size: 0.7rem;
  margin-bottom: 6px;
}

.team-carousel.is-active .person p {
  font-size: 0.8rem;
  line-height: 1.45;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* One full lap of the ellipse. Each card rests at the bottom for 3s,
   then the group swings to bring the next one down.
   Positions are written out per pose, so the transform is a pure
   translate + scale — the cards can never pick up any rotation or
   skew. The resting card scales to --orbit-focus, the others sit at
   --orbit-side / --orbit-back, and z-index rides along on the same
   keyframes so the enlarged card always paints on top.

   Each 0.7s swing is split at a 45deg arc midpoint. Without those
   midpoints the cards would travel in straight chords, cutting the
   corner of the ellipse and driving straight through each other.
   The midpoint halves are timed ease-in then ease-out, which
   recombines into one smooth ease-in-out across the whole swing. */
@keyframes team-orbit {

  0%,
  20.27% {
    transform: translate(0, var(--orbit-ry)) scale(var(--orbit-focus));
    z-index: 4;
    animation-timing-function: cubic-bezier(0.42, 0, 1, 1);
  }

  22.64% {
    transform: translate(calc(var(--orbit-rx) * var(--orbit-mid) * -1), calc(var(--orbit-ry) * var(--orbit-mid))) scale(calc((var(--orbit-focus) + var(--orbit-side)) / 2));
    z-index: 3;
    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
  }

  25%,
  45.27% {
    transform: translate(calc(var(--orbit-rx) * -1), 0) scale(var(--orbit-side));
    z-index: 2;
    animation-timing-function: cubic-bezier(0.42, 0, 1, 1);
  }

  47.64% {
    transform: translate(calc(var(--orbit-rx) * var(--orbit-mid) * -1), calc(var(--orbit-ry) * var(--orbit-mid) * -1)) scale(calc((var(--orbit-side) + var(--orbit-back)) / 2));
    z-index: 1;
    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
  }

  50%,
  70.27% {
    transform: translate(0, calc(var(--orbit-ry) * -1)) scale(var(--orbit-back));
    z-index: 1;
    animation-timing-function: cubic-bezier(0.42, 0, 1, 1);
  }

  72.64% {
    transform: translate(calc(var(--orbit-rx) * var(--orbit-mid)), calc(var(--orbit-ry) * var(--orbit-mid) * -1)) scale(calc((var(--orbit-back) + var(--orbit-side)) / 2));
    z-index: 2;
    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
  }

  75%,
  95.27% {
    transform: translate(var(--orbit-rx), 0) scale(var(--orbit-side));
    z-index: 2;
    animation-timing-function: cubic-bezier(0.42, 0, 1, 1);
  }

  97.64% {
    transform: translate(calc(var(--orbit-rx) * var(--orbit-mid)), calc(var(--orbit-ry) * var(--orbit-mid))) scale(calc((var(--orbit-side) + var(--orbit-focus)) / 2));
    z-index: 3;
    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
  }

  100% {
    transform: translate(0, var(--orbit-ry)) scale(var(--orbit-focus));
    z-index: 4;
  }
}

/* ---------- Animated gradient behind the team section ----------
   Two independently drifting layers: a wide colour sweep and a pair
   of soft "aurora" blobs. Both stay inside the section (no negative
   inset) so nothing spills into the neighbouring sections. */

@keyframes team-gradient {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

@keyframes team-aurora {
  0% {
    background-position: 0% 0%, 12% 18%, 88% 82%, 70% 8%;
  }

  50% {
    background-position: 0% 0%, 52% 78%, 48% 22%, 30% 62%;
  }

  100% {
    background-position: 0% 0%, 12% 18%, 88% 82%, 70% 8%;
  }
}

/* layer 1 — the colour sweep */
.section-alt::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: linear-gradient(115deg,
      rgba(37, 71, 190, 0.50) 0%,
      rgba(13, 120, 150, 0.50) 24%,
      rgba(122, 44, 200, 0.46) 48%,
      rgba(13, 120, 150, 0.50) 72%,
      rgba(37, 71, 190, 0.50) 100%);
  background-size: 300% 300%;
  animation: team-gradient 24s ease-in-out infinite;
}

/* layer 2 — drifting colour blobs, over a flat dark scrim that keeps
   the section copy readable no matter where the colour lands.
   The scrim is listed first (topmost) and sized 100% so animating
   background-position cannot expose its edges. */
.section-alt::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(9, 14, 30, 0.40), rgba(9, 14, 30, 0.40)),
    radial-gradient(closest-side, rgba(79, 140, 255, 0.26), transparent 72%),
    radial-gradient(closest-side, rgba(34, 211, 238, 0.22), transparent 72%),
    radial-gradient(closest-side, rgba(168, 85, 247, 0.20), transparent 72%);
  background-size: 100% 100%, 62% 78%, 54% 66%, 46% 58%;
  background-repeat: no-repeat;
  background-position: 0% 0%, 12% 18%, 88% 82%, 70% 8%;
  animation: team-aurora 19s ease-in-out infinite;
}

.section-alt>.container {
  position: relative;
  z-index: 1;
}

/* The sweep brightens the backdrop, so lift the body copy to keep it
   comfortably readable over the moving colour. */
#team .section-head p {
  color: #c5cfe6;
}

#team .eyebrow {
  color: #8df0fb;
  background: rgba(8, 16, 38, 0.62);
  border-color: rgba(141, 240, 251, 0.5);
}

.person {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 22px;
  text-align: center;
  transition: transform 0.2s ease, border-color 0.2s ease;
}

.person:hover {
  transform: translateY(-6px);
  border-color: rgba(34, 211, 238, 0.45);
}

.avatar {
  width: 74px;
  height: 74px;
  margin: 0 auto 16px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-weight: 800;
  font-size: 1.25rem;
  color: #06101f;
  background: linear-gradient(135deg, var(--brand-2), var(--brand));
}

.person h3 {
  margin-bottom: 4px;
}

.role {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  margin-bottom: 12px;
}

.person p {
  font-size: 0.88rem;
  margin: 0;
}

/* ---------- Contact section: centred heading, tighter vertical
   rhythm, because the 200px bubble travel already fills most of the
   section's height ---------- */
#contact {
  padding-top: clamp(24px, 3vw, 44px);
  padding-bottom: clamp(24px, 3vw, 44px);
}

#contact .section-head {
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 20px;
  text-align: center;
}

/* ---------- Contact bubbles ----------
   One straight row of equal circles. Every bubble travels the same
   200px up and down, but each starts a beat after the one before it,
   so the movement travels along the line as a wave. The drift
   animates the standalone `translate` property, not `transform`, so
   the :hover scale still composes on top of it. */
#contact .grid {
  --bubble-gap: 30px;
  /* the gap that sets the wave's spacing */
  --bubble-travel: 100px;
  /* how far each bubble rises and falls */
  --bubble-cycle: 6s;
  /* Fluid width so all six fit one straight row: the preferred size
     is exactly (row width - 5 gaps) / 6, clamped so the text still
     fits inside the circle. This is a WIDTH only — a percentage here
     would resolve against the container's height if used for `height`,
     so the bubble's height comes from aspect-ratio instead. */
  --bubble-w: clamp(118px, calc((100% - 5 * var(--bubble-gap)) / 6), 142px);

  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--bubble-gap);

  /* reserve exactly the room the 200px travel needs, so a bubble
     passing through the top or bottom of its swing can never reach
     the section heading or the footer */
  min-height: calc(var(--bubble-travel) * 2 + 142px);
}

@keyframes bubble-wave {

  0%,
  100% {
    translate: 0 calc(var(--bubble-travel) * -1);
  }

  50% {
    translate: 0 var(--bubble-travel);
  }
}

.contact-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: var(--bubble-w);
  aspect-ratio: 1 / 1;
  /* a true circle, derived from the width */
  /* tight padding + tight leading keeps the three text rows inside the
     circle even at the smallest size, so aspect-ratio is never
     overridden by an over-tall content box */
  padding: 16px;
  text-align: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 26%, rgba(79, 140, 255, 0.20), transparent 58%),
    linear-gradient(180deg, #1b2542 0%, #131c33 100%);
  border: 1px solid var(--line);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 10px 30px rgba(0, 0, 0, 0.28);
  animation: bubble-wave var(--bubble-cycle) ease-in-out infinite;
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

.contact-link:hover {
  transform: scale(1.07);
  border-color: rgba(79, 140, 255, 0.6);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 0 30px rgba(79, 140, 255, 0.35),
    0 16px 40px rgba(0, 0, 0, 0.35);
}

.contact-link:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 5px;
}

/* The wave. Each bubble lags the previous one by 0.225s, which is the
   30px gap covered during a 100px, 3s half-swing. It scales with
   --bubble-travel, so halving the travel keeps the ripple looking
   the same rather than stretching it across the cycle. */
.contact-link:nth-child(1) {
  animation-delay: 0s;
}

.contact-link:nth-child(2) {
  animation-delay: -0.225s;
}

.contact-link:nth-child(3) {
  animation-delay: -0.45s;
}

.contact-link:nth-child(4) {
  animation-delay: -0.675s;
}

.contact-link:nth-child(5) {
  animation-delay: -0.9s;
}

.contact-link:nth-child(6) {
  animation-delay: -1.125s;
}

.contact-label {
  font-size: 0.6rem;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--brand-2);
}

.contact-value {
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text);
  overflow-wrap: anywhere;
  /* hard ceiling at two lines: a longer address can never grow the
     content box past the circle */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.contact-hint {
  font-size: 0.62rem;
  line-height: 1.3;
  color: var(--muted);
  margin-top: 1px;
}

/* ============================================================
   FOOTER
   ============================================================ */
@keyframes footer-gradient {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

@keyframes footer-sweep {
  0% {
    background-position: 0% 50%;
  }

  100% {
    background-position: 200% 50%;
  }
}

/* The base drifts on a ping-pong: 0 -> 50 -> 100 returns to the start,
   so the ends meet seamlessly and the loop never jumps. Carrying a
   light stop at 50% is what makes the cycle read as dark -> light ->
   dark rather than a static dark wash. */
@keyframes footer-dark-light {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

.site-footer {
  position: relative;
  /* Dark -> light -> dark animated base. The gradient is larger than
     the footer and slides within itself, so it reads as a continuous
     flow rather than a band that resets. The bright stop at the
     midpoint is what carries the light half of the cycle. Sits under
     the ::before wash and scrim. */
  background-color: #05070f;
  background-image: linear-gradient(118deg,
      #04060d 0%,
      #0b1428 16%,
      #1d3a6e 32%,
      #4f7fd0 50%,
      #1d3a6e 68%,
      #0b1428 84%,
      #04060d 100%);
  background-size: 340% 340%;
  background-repeat: no-repeat;
  animation: footer-dark-light 22s ease-in-out infinite;
  padding-top: 56px;
  overflow: hidden;
}

/* layer 1 — two stacked backgrounds. The first is a fixed-size dark
   scrim that keeps footer copy readable when the light stop of the
   cycle passes underneath; it is exactly footer-sized, so the
   background-position animation has nothing to move on it. The second
   is the drifting wash. */
.site-footer::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(180deg, rgba(4, 6, 13, 0.5), rgba(4, 6, 13, 0.74)),
    linear-gradient(120deg,
      rgba(30, 48, 108, 0.55) 0%,
      rgba(14, 62, 84, 0.55) 30%,
      rgba(56, 32, 104, 0.5) 60%,
      rgba(14, 62, 84, 0.55) 85%,
      rgba(30, 48, 108, 0.55) 100%);
  background-size: 100% 100%, 300% 300%;
  animation: footer-gradient 28s ease-in-out infinite;
}

/* layer 2 — a gradient hairline that travels along the top edge */
.site-footer::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  z-index: 1;
  pointer-events: none;
  background-image: linear-gradient(90deg,
      transparent 0%,
      var(--brand-2) 25%,
      #a78bfa 50%,
      var(--brand-2) 75%,
      transparent 100%);
  background-size: 50% 100%;
  animation: footer-sweep 7s linear infinite;
}

.site-footer>.container {
  position: relative;
  z-index: 2;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.7fr 1fr 1.2fr;
  gap: 34px;
  padding-bottom: 40px;
}

.footer-brand p {
  margin-top: 16px;
  font-size: 0.92rem;
  max-width: 34ch;
}

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

/* heading gets a gradient plus a bar that grows on hover */
.footer-col h4 {
  margin-bottom: 6px;
  background-image: linear-gradient(90deg, #e8ecf6, var(--brand-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.footer-col h4::after {
  content: "";
  display: block;
  width: 0;
  height: 2px;
  margin-top: 7px;
  border-radius: 2px;
  background-image: var(--link-grad);
  transition: width 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.footer-col:hover h4::after {
  width: 48px;
}

/* ---------- Gradient link text ----------
   The gradient is twice the width of the text and the background
   position slides on hover, so the colour travels across the words
   instead of simply changing. Each column gets its own hue. */
/* Positions track the surviving columns: 1 = brand, 2 = Company, 3 = Reach Us. */
.footer-col:nth-of-type(2) {
  --link-grad: linear-gradient(90deg, #c4b5fd, #f9a8d4, #c4b5fd);
}

.footer-col:nth-of-type(3) {
  --link-grad: linear-gradient(90deg, #2dd4bf, #a3e635, #2dd4bf);
}

.footer-col a {
  position: relative;
  align-self: flex-start;
  font-size: 0.92rem;
  font-weight: 500;
  /* only lightly dimmed at rest: the hover shift reverses the
     gradient's colour order, which reads clearly on its own */
  opacity: 0.95;
  background-image: var(--link-grad);
  background-size: 200% 100%;
  background-position: 0% 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  transition: background-position 0.5s ease, transform 0.25s ease, opacity 0.25s ease;
}

.footer-col a:hover,
.footer-col a:focus-visible {
  background-position: 100% 0;
  transform: translateX(6px);
  opacity: 1;
}

.footer-col a:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 3px;
  border-radius: 3px;
}

.footer-bottom {
  display: flex;
  /* the copyright is the only thing left in this row, so centre it */
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  padding-top: 22px;
  padding-bottom: 26px;
  border-top: 1px solid var(--line);
  text-align: center;
}

.footer-bottom p {
  margin: 0;
  font-size: 0.85rem;
}

/* the logo mark gets a shifting gradient on hover */
.footer-brand .brand-mark {
  background-image: linear-gradient(135deg, var(--brand), var(--brand-2), #a78bfa);
  background-size: 200% 200%;
  transition: background-position 0.6s ease, transform 0.3s ease;
}

.footer-brand .brand-mark:hover {
  background-position: 100% 100%;
  transform: rotate(-6deg) scale(1.05);
}

/* ---------- Scroll reveal ----------
   Only applied once the script has marked the footer, so with JS
   disabled the content is simply visible. */
.site-footer.reveal-ready .footer-grid>*,
.site-footer.reveal-ready .footer-bottom {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.65s ease, transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
}

.site-footer.reveal-ready .footer-grid>.is-in,
.site-footer.reveal-ready .footer-bottom.is-in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {

  .site-footer,
  .site-footer::before,
  .site-footer::after {
    animation: none;
  }

  .site-footer.reveal-ready .footer-grid>*,
  .site-footer.reveal-ready .footer-bottom {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .footer-col a,
  .footer-col a:hover {
    transform: none;
  }
}

/* ============================================================
   SIDEBAR
   ============================================================ */
/* Drawer that slides in from the right when Login is clicked.
   `visibility` is switched with a delay rather than transitioned: on
   open the delay is 0s so the panel is focusable from the very first
   frame (which is what lets script.js focus the close button), and on
   close the delay matches the slide so the panel stays visible while
   it travels and only becomes inert once it has landed off-screen. */
.sidebar-backdrop {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(2, 5, 12, 0.62);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s ease, visibility 0s linear 0.4s;
}

.sidebar-backdrop.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.4s ease, visibility 0s;
}

.sidebar {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 90;
  width: min(340px, 86vw);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 20px 22px 26px;
  color: var(--text);
  background: radial-gradient(700px 320px at 100% 0%, rgba(79, 140, 255, 0.16), transparent 70%), linear-gradient(180deg, #0a1020 0%, #070b16 100%);
  border-left: 1px solid var(--line);
  box-shadow: -24px 0 60px rgba(0, 0, 0, 0.5);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear 0.45s;
}

.sidebar.is-open {
  transform: translateX(0);
  visibility: visible;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s;
}

.sidebar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}

.sidebar-title {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-2);
}

.sidebar-close {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  padding: 0;
  color: var(--nav-muted);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 11px;
  cursor: pointer;
  transition: color 0.25s ease, background 0.25s ease, transform 0.25s ease;
}

.sidebar-close svg {
  display: block;
  width: 17px;
  height: 17px;
}

.sidebar-close:hover,
.sidebar-close:focus-visible {
  color: #06101f;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  transform: rotate(90deg);
}

.sidebar-close:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 2px;
}

.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 20px 0 24px;
  flex: 1;
}

.sidebar-group {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.sidebar-group h4 {
  margin: 0 0 2px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: #7d8aa8;
}

.sidebar-group a {
  align-self: flex-start;
  font-size: 0.95rem;
  font-weight: 500;
  color: #c8d0e2;
  transition: color 0.22s ease, transform 0.22s ease;
}

.sidebar-group a:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Sidebar social rows ----------
   A card per network instead of a bare text link, so the four
   platforms are identifiable at a glance. Each carries its own brand
   tint through --sc (glyph), --sbg (tile) and --sbd (edge); the hex
   values are spelled out per network rather than mixed with
   color-mix(), which older browsers do not support. */
.sidebar-group a.sidebar-social {
  display: flex;
  align-items: center;
  gap: 12px;
  align-self: stretch;
  padding: 10px 12px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.07);
  transition: background 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
}

.sidebar-group a.sidebar-social:hover,
.sidebar-group a.sidebar-social:focus-visible {
  color: inherit;
  background: rgba(255, 255, 255, 0.08);
  border-color: var(--sbd);
  transform: translateX(5px);
}

.sidebar-group a.sidebar-social:focus-visible {
  outline: 2px solid var(--brand-2);
  outline-offset: 2px;
}

.sidebar-social-icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 10px;
  color: var(--sc);
  background: var(--sbg);
  border: 1px solid var(--sbd);
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.3s ease;
}

.sidebar-social-icon svg {
  display: block;
  width: 17px;
  height: 17px;
}

.sidebar-social:hover .sidebar-social-icon,
.sidebar-social:focus-visible .sidebar-social-icon {
  transform: scale(1.14);
  box-shadow: 0 0 16px var(--sbg);
}

.sidebar-social-text {
  display: flex;
  flex-direction: column;
  line-height: 1.3;
  min-width: 0;
  /* lets the handle ellipsise rather than overflow the card */
}

.sidebar-social-text strong {
  font-size: 0.93rem;
  font-weight: 600;
  color: #dbe2f0;
}

.sidebar-social-text small {
  font-size: 0.78rem;
  color: #808da9;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar-social[data-net="facebook"] {
  --sc: #6aa6ff;
  --sbg: rgba(24, 119, 242, 0.2);
  --sbd: rgba(24, 119, 242, 0.45);
}

.sidebar-social[data-net="whatsapp"] {
  --sc: #4ce07d;
  --sbg: rgba(37, 211, 102, 0.18);
  --sbd: rgba(37, 211, 102, 0.45);
}

.sidebar-social[data-net="linkedin"] {
  --sc: #63a4ff;
  --sbg: rgba(10, 102, 194, 0.24);
  --sbd: rgba(10, 102, 194, 0.5);
}

.sidebar-social[data-net="github"] {
  --sc: #d7deea;
  --sbg: rgba(255, 255, 255, 0.1);
  --sbd: rgba(255, 255, 255, 0.22);
}

/* the MB Traders page uses the house brand gradient rather than a
   third-party brand colour, since it is our own site */
.sidebar-social[data-net="mbt"] {
  --sc: #7db8ff;
  --sbg: rgba(79, 140, 255, 0.2);
  --sbd: rgba(34, 211, 238, 0.42);
}

.sidebar-foot {
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.sidebar-foot a {
  font-size: 0.88rem;
  color: var(--brand-2);
}

.sidebar-foot a:hover {
  text-decoration: underline;
}

.sidebar-foot p {
  margin: 6px 0 0;
  font-size: 0.8rem;
  color: #6f7b96;
}

/* lock the page behind the drawer so the wheel does not scroll it */
body.has-sidebar {
  overflow: hidden;
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 960px) {
  .grid-3 {
    grid-template-columns: repeat(2, 1fr);
  }

  .carousel-ring {
    grid-template-columns: repeat(2, 1fr);
  }

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

  /* keep the ring inside narrower viewports */
  .team-carousel {
    --orbit-rx: 270px;
    --orbit-ry: 100px;
    --card-w: 185px;
    --card-h: 195px;
    --orbit-focus: 1.25;
    --orbit-side: 0.6;
    --orbit-back: 0.42;
    --orbit-lift: 42px;
  }

  .team-carousel.is-active .carousel-viewport {
    height: 370px;
  }
}

@media (max-width: 720px) {
  .nav-toggle {
    display: flex;
  }

  .nav {
    position: absolute;
    top: 74px;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    /* the dropdown is part of the nav bar, so it stays black too */
    background: var(--nav-bg);
    border-bottom: 1px solid var(--nav-line);
    padding: 8px 22px 18px;
    display: none;
  }

  .nav.open {
    display: flex;
  }

  .nav>a {
    padding: 14px 0;
    border-bottom: 1px solid var(--nav-line);
  }

  .nav>a:not(.btn) {
    color: var(--nav-muted);
  }

  .nav>a:not(.btn):hover {
    color: var(--nav-text);
  }

  .nav>a:not(.btn)::after {
    display: none;
  }

  /* underline clashes with the row border */
  .nav>a:last-child {
    border-bottom: 0;
  }

  /* no double rule above the dropdown's own */

  .grid-3,
  .grid-4 {
    grid-template-columns: 1fr;
  }

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

  /* On phones the footer is just the brand, centred. The link columns
     are all reachable from the nav dropdown and the contact section,
     so dropping them keeps the footer from turning into a link farm. */
  .footer-grid {
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
  }

  .footer-col {
    display: none;
  }

  .footer-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .footer-brand .brand {
    justify-content: center;
  }

  .footer-brand .brand-text {
    align-items: center;
    text-align: center;
  }

  .footer-brand p {
    margin-left: auto;
    margin-right: auto;
    text-align: center;
  }

  .footer-bottom {
    justify-content: center;
    text-align: center;
  }

  .team-carousel {
    --orbit-rx: 138px;
    --orbit-ry: 100px;
    --card-w: 150px;
    --card-h: 215px;
    --orbit-focus: 1.1;
    --orbit-side: 0.6;
    --orbit-back: 0.42;
    --orbit-lift: 34px;
  }

  .team-carousel.is-active .carousel-viewport {
    height: 372px;
  }

  .hero-actions .btn {
    width: 100%;
    text-align: center;
  }

  /* ---------- Hero on phones ----------
     The heading sits at the clamp floor (2.1rem) on every phone, since
     5vw never reaches the preferred value below ~672px. These fixed
     sizes bring the whole block down a step and let the two buttons
     share one row instead of each taking the full width. */
  .hero {
    padding: clamp(38px, 8vw, 64px) 0;
  }

  .hero h1 {
    font-size: 1.65rem;
    line-height: 1.25;
  }

  .hero-copy p {
    font-size: 0.95rem;
    line-height: 1.55;
  }

  .hero .eyebrow {
    font-size: 0.64rem;
    padding: 4px 10px;
    margin-bottom: 14px;
  }

  .hero-actions {
    gap: 10px;
    margin-top: 20px;
  }

  /* auto width rather than 100%: at this type size both labels fit on
     one row down to a 320px phone, and stack only if they cannot.
     16px of side padding (not 18) is what keeps the pair inside 276px
     at 320px — at 18px they came to 281px and wrapped. */
  .hero-actions .btn {
    width: auto;
    padding: 10px 16px;
    font-size: 0.85rem;
  }

  /* ---------- Product cards on phones ----------
     A single full-width column leaves the 240px envelope looking squat,
     so the card drops to 195px. The letter's type is cut another step to
     pay for it, and the face icon shrinks to 38px — without that the
     icon, gap, name and paddings need 209px and would no longer fit
     inside a 195px card. */
  .card.envelope {
    height: 195px;
    perspective: 700px;
  }

  .card.envelope .env-letter {
    inset: 8px;
    padding: 12px;
  }

  .card.envelope .env-letter p {
    font-size: 0.8rem;
    line-height: 1.45;
    margin-bottom: 8px;
  }

  .card.envelope .env-letter .feature-list {
    margin-top: 8px;
    gap: 4px;
  }

  .card.envelope .env-letter .feature-list li {
    font-size: 0.76rem;
    line-height: 1.3;
    padding-left: 18px;
  }

  .card.envelope .card-icon {
    width: 38px;
    height: 38px;
    font-size: 0.8rem;
    border-radius: 11px;
  }

  .card.envelope .env-front h3 {
    font-size: 1.02rem;
  }

  /* the flap's point sits at 52% of 195px = 101px */
  .card.envelope .env-front {
    gap: 8px;
    padding: 104px 16px 14px;
  }
}

/* ---------- Reduced motion: nothing moves on its own ---------- */
@media (prefers-reduced-motion: reduce) {
  .team-carousel .carousel-item {
    animation: none;
  }

  .card,
  .contact-link {
    animation: none;
  }

  .section-alt::before,
  .section-alt::after,
  #products::before,
  #products::after {
    animation: none;
  }

  html {
    scroll-behavior: auto;
  }

  /* the envelope still opens on hover, but as a plain cross-fade
     with no sliding face and no folding flap */
  .card.envelope .env-flap {
    display: none;
  }

  .card.envelope .env-front,
  .card.envelope .env-letter {
    transform: none;
    transition: opacity 0.15s ease;
  }

  .card.envelope:hover .env-front,
  .card.envelope:focus-visible .env-front {
    opacity: 0;
  }

  .card.envelope:hover .env-letter,
  .card.envelope:focus-visible .env-letter {
    opacity: 1;
  }

  /* the drawer still opens and closes, it just arrives instead of
     sliding, and the backdrop fades without a delay */
  .sidebar,
  .sidebar-backdrop {
    transition-duration: 0.01ms;
  }

  .sidebar-close:hover,
  .sidebar-close:focus-visible,
  .sidebar-group a:hover,
  .sidebar-group a:focus-visible,
  .sidebar-group a.sidebar-social:hover,
  .sidebar-group a.sidebar-social:focus-visible,
  .sidebar-social:hover .sidebar-social-icon,
  .sidebar-social:focus-visible .sidebar-social-icon {
    transform: none;
  }
}