:root {
  --color-bg: #000000;
  --color-white: #ffffff;
  --color-bucketwise: #7bb51a;
  --color-bucketwise-rgb: 123, 181, 26;
  --color-advisormetric: #a757ee;
  --color-advisormetric-rgb: 167, 87, 238;
  --color-discipline-wealth: #8bc7d3;
  --color-discipline-wealth-rgb: 139, 199, 211;
  --color-assure-gold: #f9cd89;
  --color-assure-gold-rgb: 249, 205, 137;
  --color-inactive-bg: #374151;
  --color-inactive-text: #9ca3af;
  --radius-btn: 8px;
  --space-8: 8px;
  --space-10: 10px;
  --space-16: 16px;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  min-height: 100%;
}

body {
  background: var(--color-bg);
  color: var(--color-white);
  font-family: "Poppins", sans-serif;
  overflow-x: hidden;
}

/* The globe animation (public/js/globe.js) appends its <canvas> directly to
   <body> — pin it as a fixed, full-viewport background behind the page content. */
body > canvas {
  position: fixed;
  inset: 0;
  z-index: -1;
  display: block;
}

/* Soft atmospheric halo sitting behind the globe canvas — the globe's own
   point cloud is sparse (real city coordinates, not a filled sphere), so
   without this it can read as scattered dust rather than a lit sphere.
   Always centered on the viewport: the globe's particles are centered on
   the world origin, which projects to screen center regardless of its
   computed radius, so this never needs to track the canvas. */
body::before {
  content: "";
  position: fixed;
  top: 50%;
  left: 50%;
  width: min(85vmin, 900px);
  height: min(85vmin, 900px);
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(140, 160, 255, 0.18) 0%,
    rgba(140, 160, 255, 0.09) 40%,
    transparent 72%
  );
  z-index: -2;
  pointer-events: none;
}

/* Orbit trail lines (public/js/orbit-lines.js) — sits between the globe
   canvas (-1) and the page content (1) so trails read as passing behind
   the cards/logo but in front of the globe. Decorative only: it never
   affects layout, sizing, or interaction of anything underneath it. */
.orbit-lines {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

a {
  color: inherit;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Scales down together with the module cards' icons/text on a short
     viewport (vmin-based, same idea as .module-card__ring etc.), instead
     of staying a fixed size while everything around it shrinks. */
  gap: clamp(4px, 1vmin, 8px);
  padding: clamp(6px, 1.3vmin, 10px) clamp(10px, 2.2vmin, 16px);
  border: 0;
  border-radius: var(--radius-btn);
  font-family: inherit;
  font-weight: 600;
  font-size: clamp(11px, 1.7vmin, 14px);
  color: var(--color-white);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition:
    transform 0.15s ease,
    filter 0.15s ease,
    box-shadow 0.15s ease;
}

.btn-primary {
  background: var(--color-bucketwise);
  box-shadow: 0 4px 1.8px #3f6306;
}

.btn-primary:hover {
  transform: translateY(-2px);
  filter: brightness(1.1);
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.4);
}

.btn-primary:active {
  transform: translateY(0);
  filter: brightness(0.95);
}

.btn-disabled {
  background: var(--color-inactive-bg);
  color: var(--color-inactive-text);
  cursor: not-allowed;
}

.icon-arrow {
  width: clamp(8px, 1.2vmin, 10px);
  height: clamp(9px, 1.3vmin, 11px);
  flex-shrink: 0;
}

/* ── Landing page (index.html) ──
   Logo + trust bar centered, with the 4 module cards arranged around it. */

.landing {
  position: relative;
  z-index: 1;
  /* dvh (not vh) so mobile browser chrome doesn't leave a stray gap; this
     is a floor, not a fixed height — on a short laptop window the vmin-based
     sizes below shrink enough that content normally fits inside it anyway,
     so the page doesn't need to grow taller than the viewport and scroll. */
  min-height: 100dvh;
  display: grid;
  /* Side columns are content-sized (not 1fr) so the cards hug the center
     logo instead of stretching out to the container's full max-width. vmin
     so they also shrink together with the cards on a short viewport. */
  grid-template-columns:
    minmax(0, clamp(280px, 34vmin, 480px)) minmax(
      260px,
      clamp(320px, 42vmin, 480px)
    )
    minmax(0, clamp(280px, 34vmin, 480px));
  grid-template-areas:
    "tl . tr"
    ". center ."
    "bl . br";
  /* start, not center: every card's ring+name must line up at the same
     height within its row — only BucketWise carries the extra quote block,
     and centering would push its shorter row-mate (AdvisorMetric) down to
     compensate. Letting cards start-align keeps icons/titles level and
     lets the extra content simply extend BucketWise's card further down. */
  align-items: start;
  justify-items: center;
  /* place-content (not just justify-content) centers the whole grid block
     on BOTH axes within the viewport — so the center logo lands on the
     actual screen center at any window size/resolution, instead of being
     pinned to the top by a fixed padding. */
  place-content: center;
  /* Zero row-gap pulls the top/bottom cards vertically as close to the
     center row as their own content allows; the column-gap that pushes
     them horizontally away from the globe scales with the viewport too. */
  gap: 0px clamp(32px, 8vmin, 96px);
  max-width: 1400px;
  margin: 0 auto;
  /* Vertical padding floor kept low so it actually shrinks on short laptop
     windows instead of holding the page taller than 100dvh (which forces a
     vertical scrollbar even though place-content: center is meant to fit
     everything without one). */
  padding: clamp(0.6rem, 2.4vmin, 3rem) clamp(1rem, 4vw, 2rem);
}

.landing__center {
  grid-area: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(10px, 2vmin, 16px);
  text-align: center;
  /* Mathematically centered reads as slightly low/left because of the
     logo's own asymmetric shape (the "P" mark's visual weight leans
     bottom-left) — nudge up and right so it reads as optically centered. */
  transform: translate(clamp(6px, 1vmin, 14px), clamp(-14px, -1.6vmin, -6px));
}

.landing__center .logo {
  width: clamp(220px, 34vmin, 480px);
  height: auto;
}

.trust-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  /* nowrap: a flex row's min-content shrinks to its widest single item
     once wrapping is allowed, which lets the grid center column below
     squeeze narrower than this row actually needs and wrap it — keeping
     it on one line forces the column to size to fit it instead. */
  flex-wrap: nowrap;
  gap: 14px;
}

.trust-bar__item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  white-space: nowrap;
}

.trust-bar__icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.trust-bar__divider {
  width: 1px;
  height: 17px;
  background: rgba(255, 255, 255, 0.35);
  flex-shrink: 0;
}

/* ── Module cards ── */

.module-card {
  grid-area: var(--card-area);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(7px, 2vmin, 18px);
  text-align: center;
  /* Lets the ring's hover rotateY (below) render with real depth instead
     of looking like a flat horizontal squash. */
  perspective: 700px;
}

.module-card--tl {
  --card-area: tl;
}

.module-card--tr {
  --card-area: tr;
}

.module-card--bl {
  --card-area: bl;
}

.module-card--br {
  --card-area: br;
}

.module-card--bucketwise {
  --card-accent-rgb: var(--color-bucketwise-rgb);
}

.module-card--advisormetric {
  --card-accent-rgb: var(--color-advisormetric-rgb);
}

.module-card--discipline-wealth {
  --card-accent-rgb: var(--color-discipline-wealth-rgb);
}

.module-card--discipline-assured {
  --card-accent-rgb: var(--color-assure-gold-rgb);
}

.module-card--inactive {
  opacity: 0.85;
}

/* Hover only ever touches the icon ring (badge rides along as its child) —
   the card's text/button stay put. A pure, moderate rotateY is a rotation
   around the vertical axis, so it reads as the icon turning left-right
   ("horizontally") for as long as it's hovered, never stretching/skewing
   the way animating the whole (text-containing) card did. */
.module-card__ring {
  position: relative;
  /* Floor kept low on purpose (well below the 16.5vmin/228px preferred/max
     size) — it's a safety minimum, not the everyday size. A higher floor
     was overriding the fluid vmin size on short laptop windows and pushing
     the page past 100dvh into a vertical scrollbar. */
  width: clamp(76px, 16.5vmin, 228px);
  aspect-ratio: 1;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid rgba(var(--card-accent-rgb), 0.55);
  box-shadow: 0 0 24px -4px rgba(var(--card-accent-rgb), 0.55);
  background: radial-gradient(
    circle at 50% 40%,
    rgba(var(--card-accent-rgb), 0.14),
    transparent 70%
  );
  transition:
    transform 0.4s ease,
    box-shadow 0.35s ease,
    border-color 0.35s ease;
}

.module-card:hover .module-card__ring,
.module-card:focus-within .module-card__ring {
  transform: rotateY(25deg);
  border-color: rgba(var(--card-accent-rgb), 0.9);
  box-shadow: 0 0 40px -2px rgba(var(--card-accent-rgb), 0.85);
}

.module-card__badge {
  width: 90%;
  height: 90%;
  object-fit: contain;
  /* Painted after (on top of) the orbit elements below in DOM order, so it
     stays crisp above the thin orbit ellipse/dot without needing z-index. */
  position: relative;
}

/* Decorative "satellite orbit" around each icon ring — purely additive, it
   sits outside the ring's own box (inset < 0) so it never affects the
   ring/card's size or the rest of the layout. Bolder border + soft glow so
   it actually reads as a lit halo (reference image) instead of a barely
   visible hairline. */
.module-card__orbit {
  position: absolute;
  inset: -18%;
  border-radius: 50%;
  border: 1.5px solid rgba(var(--card-accent-rgb), 0.5);
  box-shadow: 0 0 14px 0 rgba(var(--card-accent-rgb), 0.35);
  transform: scaleY(0.4);
  pointer-events: none;
}

/* Bright arc segment that sweeps continuously around the ring, like a
   comet-lit edge of a Saturn-style ring — layered inside .module-card__orbit
   so it inherits the same scaleY(0.4) flattening and reads as part of the
   same tilted ellipse. Masked down to a ring (not a filled disc) via
   radial-gradient mask. */
.module-card__orbit::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    transparent 0deg,
    rgba(var(--card-accent-rgb), 0) 20deg,
    rgba(var(--card-accent-rgb), 1) 90deg,
    rgba(var(--card-accent-rgb), 0) 160deg,
    transparent 360deg
  );
  -webkit-mask: radial-gradient(
    closest-side,
    transparent calc(100% - 3px),
    #000 calc(100% - 3px)
  );
  mask: radial-gradient(
    closest-side,
    transparent calc(100% - 3px),
    #000 calc(100% - 3px)
  );
  filter: blur(1px);
  animation: orbit-glow-spin 6s linear infinite;
  pointer-events: none;
}

/* Same box as .module-card__orbit — its own center is animated along an
   ellipse matching that ring's shape, dragging the small dot (::before,
   pinned at its center) along for the ride. */
.module-card__orbit-track {
  position: absolute;
  inset: -18%;
  offset-path: ellipse(50% 20% at 50% 50%);
  animation: orbit-spin 7s linear infinite;
  pointer-events: none;
}

.module-card__orbit-track::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  background: rgb(var(--card-accent-rgb));
  box-shadow: 0 0 12px 4px rgba(var(--card-accent-rgb), 0.9);
}

@keyframes orbit-spin {
  to {
    offset-distance: 100%;
  }
}

@keyframes orbit-glow-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Fixed-height, vertically-centered slot for the product name — guarantees
   every card's "Sign In" button lands on a consistent row regardless of
   whether the name wraps to one line (BucketWise, AdvisorMetric) or two
   (the Discipline products), matching the Figma reference. */
.module-card__name-slot {
  font-size: clamp(14px, 2.3vmin, 26px);
  line-height: 1.2;
  min-height: 2.4em;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
}

.module-card__name {
  margin: 0;
  font-weight: 600;
  white-space: nowrap;
  text-align: center;
}

.module-card__name .accent-green {
  color: var(--color-bucketwise);
}

.module-card__name .accent-purple {
  color: var(--color-advisormetric);
}

.module-card__name .accent-gold {
  color: var(--color-assure-gold);
}

.module-card__name sup {
  font-size: 0.6em;
}

.module-card__category {
  margin: 0;
  font-weight: 400;
  font-size: 0.6em;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

/* Respect reduced-motion preferences: keep the glow feedback, drop the turn
   and the orbit/trail motion (the static ring outline stays visible). */
@media (prefers-reduced-motion: reduce) {
  .module-card__ring {
    transition:
      box-shadow 0.2s ease,
      border-color 0.2s ease;
  }

  .module-card:hover .module-card__ring,
  .module-card:focus-within .module-card__ring {
    transform: none;
  }

  .module-card__orbit-track {
    animation: none;
    offset-distance: 0%;
  }

  .module-card__orbit::before {
    animation: none;
  }
}

/* Below this width the 3-column radial grid gets cramped against the card
   text — collapse to the logo on its own row, then the 4 cards as a 2×2
   grid underneath. */
@media (max-width: 900px) {
  .landing {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas:
      "center center"
      "tl tr"
      "bl br";
    /* Wider gaps than desktop between the stacked cards (and between the
       PurposeOS logo and the first card, since row-gap applies to every
       row uniformly) — desktop centers via place-content, but mobile's
       stacked content is routinely taller than one screen, so that alone
       doesn't stop the page opening scrolled to the very top of the grid.
       Generous top padding instead just gives the logo breathing room from
       the top edge — intentionally NOT centered vertically. */
    gap: 88px 24px;
    padding-top: clamp(4rem, 15dvh, 10rem);
    padding-bottom: clamp(3rem, 12dvh, 7rem);
  }

  /* The parabola-style trail lines to the globe (public/js/orbit-lines.js)
     are tuned for the desktop radial layout — on the stacked mobile grid
     they cross over unrelated cards and text. Keep only the per-icon
     orbit ring/dot (.module-card__orbit-track), which stays self-contained
     to each card regardless of layout. */
  .orbit-lines {
    display: none;
  }

  /* The 4 module cards read as too small on mobile once they're stacked
     one-per-row instead of arranged around the globe — roughly double the
     icon ring here specifically (the desktop clamp's floor is tuned for
     the radial layout, not a full-width stacked card). Name/category text
     and the button scale up too, but only modestly at this 2-column
     sub-breakpoint (each card gets ~half the viewport here) — the name is
     `white-space: nowrap` (e.g. "ASSURED SOLUTIONS™"), so too big a font
     overflows its column and collides with its neighbor. The bigger, closer
     to 2x bump for name/button lives in the max-width:480px block below,
     once each card gets the full row to itself. */
  .module-card__ring {
    width: clamp(150px, 34vmin, 300px);
  }

  .module-card__name-slot {
    font-size: clamp(18px, 3.2vmin, 25px);
  }

  .btn {
    gap: clamp(5px, 1.3vmin, 10px);
    padding: clamp(8px, 1.8vmin, 13px) clamp(13px, 3vmin, 20px);
    font-size: clamp(13px, 2.2vmin, 17px);
  }

  .icon-arrow {
    width: clamp(10px, 1.6vmin, 13px);
    height: clamp(11px, 1.8vmin, 14px);
  }
}

/* Below this width even the 2×2 grid columns are narrower than the nowrap
   card text (e.g. "DISCIPLINE ASSURED SOLUTIONS"), pushing it past the
   viewport edge — drop to a single column so each card gets the full row
   width. */
@media (max-width: 480px) {
  .landing {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "center"
      "tl"
      "tr"
      "bl"
      "br";
    gap: 96px;
  }

  /* Each card now has the full row width to itself, so the name text (and
     the icon ring/button) can grow further than the 2-column breakpoint
     above without its nowrap text overflowing into anything else. */
  .module-card__ring {
    width: clamp(160px, 42vmin, 260px);
  }

  .module-card__name-slot {
    font-size: clamp(24px, 6.5vmin, 32px);
  }

  .btn {
    gap: clamp(6px, 1.8vmin, 12px);
    padding: clamp(10px, 2.6vmin, 16px) clamp(16px, 4vmin, 24px);
    font-size: clamp(16px, 3vmin, 21px);
  }

  .icon-arrow {
    width: clamp(12px, 2.2vmin, 15px);
    height: clamp(13px, 2.4vmin, 16px);
  }
}
