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

:root{
  --gutter:25;
  --u:max(min(.72px, calc(100vh / 700)), min(calc(100vw / 1353), calc(100vh / 1163)));
  --dh-px:calc(1163 * var(--u));
  --vshift:calc(max(0px, (100vh - var(--dh-px))) * .42);
  --ink:#ffffff; --cyan:#C4AB82;
  /* The site's original dark navy — page background, old dark-theme
     sections. Named so other stylesheets (e.g. light-theme.css) can match
     it exactly by value without depending on this file's cascade. */
  --navy:#04101f;
  --btn-ink:#071227;
  --font-serif:'Prata', Georgia, serif;
  --font-body:'Hanken Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-logo:'Poppins', sans-serif;
  --nav-h:76px;
}
@media (max-width:640px){ :root{ --nav-h:64px; } }
@supports (height:100dvh){
  :root{
    --u:max(min(.72px, calc(100dvh / 700)), min(calc(100vw / 1353), calc(100dvh / 1163)));
    --vshift:calc(max(0px, (100dvh - var(--dh-px))) * .42);
  }
}
html{height:100%; scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }
body{margin:0; min-height:100%; overflow-x:hidden; background:var(--navy); color:var(--ink); font-family:var(--font-body);
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  text-rendering:geometricPrecision}

/* ============ HERO STAGE ============ */
.stage{position:relative; width:100%; height:100vh; overflow:hidden; isolation:isolate}
@supports (height:100dvh){ .stage{height:100dvh} }
.sky{position:absolute; inset:0; z-index:0}
.sky::before{content:""; position:absolute; inset:0; z-index:0;
  background-image:var(--sky-bg, none); background-size:cover; background-position:center;
  background-repeat:no-repeat}
/* Venus's still/poster render has its shadow on the wrong side — mirror just this layer */
body[data-planet="venus"] .sky::before{transform:scaleX(-1)}
.sky video{position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  display:block; opacity:0; transition:opacity .22s linear; z-index:1}
.sky video.is-active{opacity:1}
@media (prefers-reduced-motion:reduce){ .sky video{display:none} }
/* Earth's and Mars's source footage brings the planet's horizon into frame
   noticeably higher than Venus's — measured directly against the poster
   stills (the same frame the video's own first paint uses): horizon sits
   at ~55.3% down the frame for Earth, ~55.7% for Mars, vs ~61.4% for
   Venus. Combined with the CTA button's fixed position in this
   (non-phone) layout — .cta's own bottom edge sits at a fixed ~57% down
   the same viewport-cover-mapped frame, from (597+66)/1163 in the hero's
   design-height units — Earth/Mars leave the button sitting at or past
   the horizon instead of clear above it, unlike Venus. Zooming in 11%
   from a top-anchored origin leaves the top of frame (deep space) exactly
   where it was and pushes the horizon down to ~61.4%, matching Venus,
   without needing different footage — .stage's overflow:hidden clips the
   extra height this adds below frame. Scoped to the non-phone hero layout
   (mirrors the phone breakpoint's own condition, negated) because that's
   where .cta actually holds this fixed position; phone's stacked flex
   layout positions the CTA from the content above it instead, so this
   specific conflict doesn't obviously apply there the same way — flagged,
   not applied, pending an actual look at phone width. */
@media (min-width:580px) and (min-height:621px){
  body[data-planet="earth"] .sky::before, body[data-planet="earth"] .sky video,
  body[data-planet="mars"] .sky::before, body[data-planet="mars"] .sky video{
    transform-origin: 50% 0%;
    transform: scale(1.11);
  }
}
/* Saturn's and Cortex's source footage has the same too-high horizon as
   Earth/Mars originally did — measured the same way against their poster
   stills: ~55.1% down for Saturn, ~55.3% for Cortex, vs the ~61.4% target.
   Same top-anchored push-down fix, but scaleY only, not a uniform scale:
   Saturn's rings already reach both left and right edges of the source
   frame (measured: they span the full 2560px width at the ring plane), so
   the horizontal component of a uniform scale(1.11) would crop into the
   ring tips exactly where they're least able to spare it. Scaling only Y
   reproduces the identical vertical repositioning math (a point at
   fraction f down the frame still moves to f*1.11 down it) without
   touching width at all, at the cost of a mild vertical stretch instead
   of a horizontal crop — the explicit tradeoff asked for here. Applied to
   both branches for consistency rather than using scale() for Cortex
   alone (its content does have a little more side margin, but not enough
   to be worth two different transform strategies for two planets fixed
   together). */
@media (min-width:580px) and (min-height:621px){
  body[data-planet="saturn"] .sky::before, body[data-planet="saturn"] .sky video,
  body[data-planet="cortex"] .sky::before, body[data-planet="cortex"] .sky video{
    transform-origin: 50% 0%;
    transform: scaleY(1.11);
  }
}

.ui{position:absolute; inset:0; z-index:3}

/* LAYOUT */
.copy{position:absolute; inset:0; transform:translateY(var(--vshift)); pointer-events:none}
.copy a{pointer-events:auto}
.col{position:absolute; left:0; right:calc(var(--gutter) * var(--u)); text-align:center}

/* HERO COPY */
.eyebrow{top:calc(188.8 * var(--u)); font-size:calc(30.45 * var(--u)); font-weight:500;
  line-height:1; letter-spacing:calc(4 * var(--u)); text-indent:calc(4 * var(--u)); color:#fff}
h1.title{top:calc(270 * var(--u)); font-family:var(--font-serif); font-weight:400;
  font-size:calc(112.4 * var(--u) * var(--title-scale, 1)); line-height:1; letter-spacing:calc(2 * var(--u));
  text-indent:calc(2 * var(--u)); color:#fff}
h1.title .ent-line{display:inline-block}
/* Non-Home branches: was 250u (a since-reverted 18u "general nudge up"
   that shifted this from an original, deliberately-tight 268u). That
   nudge left only 250-258.8=-8.8u of clearance under the 70u-tall eyebrow
   logo-mark (188.8u eyebrow top + 70u logo height = 258.8u bottom edge),
   i.e. the title was actually overlapping the logo above it. Back to
   ~268u (rounded to 270u) restores the original ~11u breathing room
   there. Home is unaffected: its eyebrow is left empty (logo lives in
   the title slot instead — see index.html), so it has its own override
   below and was never part of this overlap. */
body[data-planet="earth"] h1.title{top:calc(182 * var(--u))}

/* top was 433.2u; pulled up to tighten the gap under the title (now that
   the title itself sits lower again, see h1.title above) — same 33.2u
   shift as .cta below, so the lede-to-cta gap this preserved unchanged,
   only the title-to-lede gap shrinks. */
p.lede{top:calc(400 * var(--u)); font-size:calc(24 * var(--u)); font-weight:400;
  line-height:calc(38 * var(--u)); color:rgba(255,255,255,.95)}

/* CTA ROW */
/* top was 597u (bottom edge at (597+66)/1163 ≈ 57% down frame); moved up
   to clear the ~55% horizon Saturn/Cortex/Earth/Mars sit at before the
   1.11 zoom-in fix below applies (min-height:621px gate) — at any width
   above the orbit-nav's 1250px panel-switch breakpoint that gate is
   already satisfied by ordinary window heights, but this keeps the
   button clear of the horizon even in the unscaled case instead of
   depending on that fix always being active. Then 540u; now pulled up a
   further 33.2u to follow p.lede's own move up above by the same amount,
   keeping the lede-to-cta gap exactly as it was rather than letting it
   grow. Still well clear of the horizon: bottom edge lands at
   (507+66)/1163 ≈ 49.3% down frame, i.e. more clearance than before, not
   less. */
.cta{top:calc(507 * var(--u)); height:calc(66 * var(--u)); isolation:isolate}
.cta a{display:inline-flex; align-items:center; justify-content:center;
  width:calc(216 * var(--u)); height:calc(66 * var(--u)); border-radius:calc(33 * var(--u));
  font-size:calc(17 * var(--u)); font-weight:700; letter-spacing:0; text-indent:0;
  line-height:1; color:var(--btn-ink); text-decoration:none; padding-top:calc(2 * var(--u));
  background:linear-gradient(180deg,#ffffff 0%,#d6e8f8 4%,#d9ecfe 72%,#ffffff 100%);
  box-shadow:0 calc(10 * var(--u)) calc(18 * var(--u)) calc(-8 * var(--u)) rgba(255,255,255,.50),
             0 0 calc(26 * var(--u)) rgba(255,255,255,.18),
             inset 0 0 0 calc(2 * var(--u)) rgba(255,255,255,.9)}
/* FOCUS */
.cta a:focus-visible{
  outline:2px solid var(--cyan); outline-offset:3px}

/* ============ HERO RESPONSIVE ============ */

/* TABLET */
@media (min-width:580px) and (max-width:1030px) and (min-height:621px){
  :root{--gutter:0;
    --u:min(max(min(.85px, calc(100vh / 780)), min(calc(100vw / 900), calc(100vh / 1163))), 1.15px);
    --dh-px:calc(1120 * var(--u));
    --vshift:calc(max(0px, (100vh - var(--dh-px))) * .38)}
  @supports (height:100dvh){
    :root{--gutter:0;
      --u:min(max(min(.85px, calc(100dvh / 780)), min(calc(100vw / 900), calc(100dvh / 1163))), 1.15px);
      --dh-px:calc(1120 * var(--u));
      --vshift:calc(max(0px, (100dvh - var(--dh-px))) * .38)}
  }
  p.lede br{display:none}
  p.lede{max-width:calc(620 * var(--u)); margin-left:auto; margin-right:auto; text-wrap:pretty}
}

/* Above the tablet block but still under the orbit-nav's panel-switch
   breakpoint (max-width:1250px): p.lede has no max-width in the default
   (>1030px) rule below, so long-copy branches (e.g. Cortex, Venus) can
   render an unwrapped line wide enough to reach under the orbit-nav even
   though the vertical panel hasn't appeared yet at these widths. Same cap
   the tablet block already uses, just carried through this gap. */
@media (min-width:1031px) and (max-width:1250px){
  p.lede br{display:none}
  p.lede{max-width:calc(620 * var(--u)); margin-left:auto; margin-right:auto; text-wrap:pretty}
}

/* PHONE */
@media (max-width:579px), (max-height:620px){
  :root{--gutter:0;
    --u:max(min(.92px, calc(100vh / 620)), min(calc(100vw / 430), calc(100vh / 880)));
    --dh-px:calc(880 * var(--u));
    --vshift:calc(max(0px, (100vh - var(--dh-px))) * .34)}
  @supports (height:100dvh){
    :root{--gutter:0;
      --u:max(min(.92px, calc(100dvh / 620)), min(calc(100vw / 430), calc(100dvh / 880)));
      --dh-px:calc(880 * var(--u));
      --vshift:calc(max(0px, (100dvh - var(--dh-px))) * .34)}
  }
  .copy{top:calc(76 * var(--u)); display:flex; flex-direction:column; align-items:center;
    padding:calc(56 * var(--u)) calc(26 * var(--u)) 0}
  .col{position:static; width:100%; right:auto}
  .eyebrow{font-size:calc(20 * var(--u)); letter-spacing:calc(5 * var(--u)); text-indent:calc(5 * var(--u))}
  h1.title{font-size:calc(86 * var(--u) * var(--title-scale, 1)); margin-top:calc(18 * var(--u))}
  p.lede{margin-top:calc(10 * var(--u)); font-size:calc(20 * var(--u));
    line-height:calc(32 * var(--u)); max-width:calc(400 * var(--u)); text-wrap:balance}
  p.lede br{display:none}
  .cta{top:auto; margin-top:calc(18 * var(--u)); height:calc(60 * var(--u)); position:relative}
  .cta a{width:calc(190 * var(--u)); height:calc(60 * var(--u)); border-radius:calc(30 * var(--u))}
}

/* SHORT */
@media (max-height:620px){
  :root{--u:max(min(.85px, calc(100vh / 470)), min(calc(100vw / 640), calc(100vh / 560)));
    --dh-px:calc(560 * var(--u)); --vshift:0px}
  .copy{padding-top:calc(26 * var(--u))}
  h1.title{font-size:calc(64 * var(--u) * var(--title-scale, 1)); margin-top:calc(10 * var(--u))}
  p.lede{margin-top:calc(7 * var(--u))}
  .cta{margin-top:calc(12 * var(--u))}
}
@media (min-width:821px) and (max-height:660px){ .copy{transform:none} }

/* ============ SHARED SECTION STYLES ============ */
.wrap2{max-width:1180px; margin:0 auto; padding:0 clamp(20px,4vw,48px)}
.eyebrow2{font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:var(--cyan);
  display:flex; align-items:center; gap:10px; margin-bottom:16px; font-weight:600}
.eyebrow2::before{content:""; width:24px; height:1px; background:currentColor}
.section-head{display:flex; justify-content:space-between; align-items:flex-end; gap:24px;
  flex-wrap:wrap; margin-bottom:44px}
.section-head .num{font-size:13px; letter-spacing:.08em; text-transform:uppercase;
  color:rgba(255,255,255,.5); font-weight:600}
.section-head h2{font-family:var(--font-serif); font-weight:400; text-transform:uppercase;
  font-size:clamp(26px,4vw,42px); margin-top:8px; line-height:1.08}
.btn-ghost{display:inline-block; font-size:13px; text-transform:uppercase; letter-spacing:.05em;
  font-weight:600; padding:12px 20px; border:1px solid rgba(255,255,255,.3); color:#fff;
  text-decoration:none; background:none; cursor:pointer}
.btn-ghost:hover{border-color:#fff}
.chip-row{display:flex; gap:10px; flex-wrap:wrap; margin:22px 0 0}
.chip{font-size:12px; text-transform:uppercase; letter-spacing:.05em;
  border:1px solid rgba(255,255,255,.25); padding:8px 14px; color:rgba(255,255,255,.75)}
.note-row{margin-top:40px; padding-top:28px; border-top:1px solid rgba(255,255,255,.1);
  display:flex; justify-content:space-between; gap:24px; flex-wrap:wrap; align-items:center}
.note-row p{max-width:560px; font-size:14px; line-height:1.6; color:rgba(255,255,255,.65); margin:0}

/* ============ DETAIL SECTIONS ============ */
.detail{padding:96px 0; border-bottom:1px solid rgba(255,255,255,.08); scroll-margin-top:var(--nav-h)}
.detail.alt{background:#0a1830}
.detail-hero p.lede2{font-size:16px; line-height:1.6; color:rgba(255,255,255,.75); max-width:680px;
  margin-bottom:48px}

/* marketplace service cards */
.svc-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:22px}
@media (max-width:860px){ .svc-grid{grid-template-columns:1fr} }
.svc-card{border:1px solid rgba(255,255,255,.12); padding:26px 24px; background:rgba(255,255,255,.02)}
.svc-card .idx{display:block; font-size:12px; color:var(--cyan); margin-bottom:10px;
  font-weight:600; letter-spacing:.03em}
.svc-card h3{font-family:var(--font-serif); font-weight:400; text-transform:uppercase;
  font-size:21px; margin:0 0 12px}
.svc-card p{font-size:14.5px; line-height:1.55; color:rgba(255,255,255,.75); margin:0 0 14px}
.svc-card ul{margin:0; padding-left:18px; font-size:13.5px; line-height:1.7; color:rgba(255,255,255,.78)}

.included{display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.12); margin-top:32px}
@media (max-width:860px){ .included{grid-template-columns:1fr 1fr} }
.included div{background:#0a1830; padding:16px 18px}
.included .k{display:block; font-size:11px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--cyan); margin-bottom:6px; font-weight:600}
.included .v{font-size:13px; line-height:1.4; color:rgba(255,255,255,.75)}

.steps{display:grid; grid-template-columns:repeat(6,1fr); border-top:1px solid rgba(255,255,255,.1);
  margin-top:48px}
@media (max-width:900px){ .steps{grid-template-columns:repeat(2,1fr)} }
.step{padding:20px 18px; border-right:1px solid rgba(255,255,255,.1); border-bottom:1px solid rgba(255,255,255,.1)}
.step .n{font-size:12px; color:var(--cyan); font-weight:600}
.step h4{font-family:var(--font-serif); font-weight:400; text-transform:uppercase; font-size:16px; margin:8px 0 8px}
.step p{font-size:12.5px; line-height:1.5; color:rgba(255,255,255,.6); margin:0}

.commit-grid{display:grid; grid-template-columns:repeat(2,1fr); gap:22px; margin-top:48px}
@media (max-width:760px){ .commit-grid{grid-template-columns:1fr} }
.commit{border-left:2px solid var(--cyan); padding-left:18px}
.commit .n{font-size:12px; color:var(--cyan); font-weight:600}
.commit h4{font-size:18px; margin:6px 0 8px; font-weight:600}
.commit p{font-size:14px; line-height:1.55; color:rgba(255,255,255,.65); margin:0}

.quote-block{margin-top:56px; padding-top:40px; border-top:1px solid rgba(255,255,255,.1)}
.quote-block p.quote{font-family:var(--font-serif); font-weight:400; font-size:clamp(20px,3vw,30px);
  line-height:1.35; max-width:800px; margin:0 0 18px}
.quote-attr{font-size:13px; color:rgba(255,255,255,.55)}

.sub-block{margin-top:80px; padding-top:56px; border-top:1px solid rgba(255,255,255,.1)}

/* ============ ABOUT ============ */
.about-hero{padding:calc(var(--nav-h) + 74px) 0 60px; scroll-margin-top:var(--nav-h)}
.about-hero h1{font-family:var(--font-serif); font-weight:400; text-transform:uppercase;
  font-size:clamp(34px,6vw,60px); margin:0 0 20px; line-height:1.04}
.about-hero h1 em{font-style:normal; color:var(--cyan)}
.about-hero p{font-size:16px; line-height:1.6; color:rgba(255,255,255,.75); max-width:720px}
.team{padding:10px 0 100px}
.team-grid{display:grid; grid-template-columns:repeat(4,1fr); gap:24px; margin-top:8px}
@media (max-width:980px){ .team-grid{grid-template-columns:repeat(2,1fr)} }
@media (max-width:600px){ .team-grid{grid-template-columns:1fr} }
.team-card2{background:#0d1f3a; border:1px solid rgba(255,255,255,.1)}
.team-photo2{position:relative; width:100%; aspect-ratio:4/5; overflow:hidden}
.team-photo2 img{width:100%; height:100%; object-fit:cover; display:block}
.team-photo2::after{content:""; position:absolute; left:0; right:0; bottom:0; height:46%;
  background:linear-gradient(to top, rgba(4,16,31,.92), rgba(4,16,31,0))}
.role-tag2{position:absolute; left:16px; bottom:14px; z-index:2; font-size:11px;
  text-transform:uppercase; letter-spacing:.06em; color:var(--cyan); font-weight:600}
.team-body2{padding:20px 20px 24px}
.team-body2 h3{font-family:var(--font-serif); font-weight:400; text-transform:uppercase;
  font-size:20px; margin:0 0 12px}
.team-body2 p{font-size:13px; line-height:1.6; color:rgba(255,255,255,.7); margin:0 0 12px}
.team-body2 p:last-child{margin-bottom:0}

/* ============ CONTACT / FOOTER ============
   Minimal, Cin7-style: logo + copyright + Legal/Privacy links on the
   left, a divider, icon-button social links on the right. Nothing else —
   no headline, no CTA copy, no buttons beyond the social icons. The
   "You've proven your product..." CTA that used to live here (and, for
   one round, in a standalone .cta-banner section on E-Commerce) has been
   removed outright — E-Commerce's own light-grid closing CTA covers the
   same ground. */
.contact{padding:48px 0; background:var(--navy);
  border-top:1px solid rgba(255,255,255,.08); scroll-margin-top:var(--nav-h)}
.foot-bottom{display:flex; align-items:center; justify-content:space-between;
  flex-wrap:wrap; gap:24px}
.foot-brand{display:flex; align-items:center; gap:20px; flex-wrap:wrap}
.foot-logo{height:22px; width:auto; display:block}
.foot-copyright, .foot-tagline{font-size:13px; color:rgba(255,255,255,.5)}
.foot-legal{display:flex; gap:20px}
.foot-legal a{font-size:13px; color:rgba(255,255,255,.5); text-decoration:none}
.foot-legal a:hover{color:#fff; text-decoration:underline}
.foot-divider{width:1px; height:24px; background:rgba(255,255,255,.15)}
.foot-social-icons{display:flex; gap:12px}
.social-icon-btn{display:inline-flex; align-items:center; justify-content:center;
  width:38px; height:38px; border-radius:50%; border:1px solid rgba(255,255,255,.2);
  color:rgba(255,255,255,.7); transition:border-color .2s, color .2s}
.social-icon-btn:hover{border-color:rgba(255,255,255,.6); color:#fff}
.social-icon-btn svg{width:16px; height:16px; fill:currentColor; display:block}
@media (max-width:560px){
  .foot-bottom{justify-content:center; text-align:center}
  .foot-divider{display:none}
}

/* ============ ENTRANCE ANIMATION ============ */
@keyframes ent-reveal{from{transform:translateY(115%)}to{transform:translateY(0)}}
@keyframes ent-rise{from{opacity:0;transform:translateY(var(--rise,10px))}to{opacity:1;transform:none}}
@keyframes ent-settle{from{opacity:0;transform:translateY(var(--rise,8px)) scale(.965)}to{opacity:1;transform:none}}
@keyframes ent-fade{from{opacity:0}to{opacity:1}}

.anim{--e-expo:cubic-bezier(.16,1,.3,1); --e-quint:cubic-bezier(.22,1,.36,1);
      --e-slow:cubic-bezier(.4,0,.2,1)}
.ent-mask,.ent-line{display:block}
.anim .ent-mask{overflow:hidden; padding-top:.18em; margin-top:-.18em}
.anim .ent-line{transform:translateY(115%); will-change:transform}
.anim p.lede,.anim .cta a,.anim .sky{opacity:0}
.anim .sky{will-change:opacity}

.anim.play .sky{animation:ent-fade 1.6s var(--e-slow) .25s both}
.anim.play .eyebrow .ent-line{animation:ent-reveal .75s var(--e-expo) .30s both}
.anim.play h1.title .ent-line{animation:ent-reveal .95s var(--e-expo) .44s both}
.anim.play p.lede{--rise:12px; animation:ent-rise .7s var(--e-quint) .86s both}
.anim.play .cta a{--rise:8px; animation:ent-settle .7s var(--e-quint) 1.14s both}

/* ============ SECTION HEADLINE REVEAL (scroll-triggered) ============ */
/* Same masked slide-up mechanic and timing as the hero title's own
   entrance (h1.title .ent-line above: ent-reveal, .95s, same easing),
   reused for every .lp-headline site-wide (site.js finds them by that
   class alone, so new headlines added on any page pick this up with no
   per-page wiring). Can't reuse the hero's <html>.anim/.play toggle
   directly though: that's a one-shot page-load choreography which
   removes itself from <html> ~2s after playing, while these headlines
   sit below the fold and get scrolled into view arbitrarily later —
   often well after that toggle is already gone. .headline-mask/
   .headline-line are a separate, permanent copy of the same
   .ent-mask/.ent-line structure instead, kept live indefinitely and
   triggered per-element by IntersectionObserver (site.js) adding
   .in-view the first time each headline scrolls into view, once only
   (site.js unobserves immediately after). Easing is hardcoded here
   rather than reusing var(--e-expo) — that variable only exists while
   <html> still has .anim, which this is deliberately independent of.
   site.js wraps each .lp-headline's existing content in this structure
   at init; no markup changes needed in any page. */
.headline-mask{display:block; overflow:hidden; padding-top:.18em; margin-top:-.18em}
.headline-line{display:block; transform:translateY(115%); will-change:transform}
.headline-line.in-view{animation:ent-reveal .95s cubic-bezier(.16,1,.3,1) both}

/* ============ LOGO (in-flow, same slot/size on every branch) ============ */
.eyebrow .logo-mark{display:inline-block; height:calc(70 * var(--u)); width:auto}
/* Home: logo moves into the title slot (via JS) at the title's own scale */
h1.title .logo-mark{display:inline-block;
  height:calc(160 * var(--u) * var(--title-scale, 1)); width:auto}

/* ============ ORBIT NAV (side planetary panel) ============ */
/* Same real-image-as-circle technique as the pre-rebuild .planet buttons —
   see git history (commit 0f6d1d0) for the original two-slot version this
   is ported from. Circles are the source PNGs, not a CSS mask/crop. */
.hero-wrap{position:relative}
/* Fixed (not absolute) so the panel stays visible for the entire page
   scroll on every page, not just while the hero itself is in view —
   position:fixed is viewport-relative, so top/right below pin it to the
   same on-screen spot regardless of scroll position. z-index:60 is
   already comfortably above everything else on the page (nothing else
   here goes past z-index:3), so it stays on top at every scroll depth
   without needing a bump. */
.orbit-panel{position:fixed; top:calc(var(--nav-h) + 24px); right:0; z-index:60;
  display:flex; flex-direction:column; align-items:flex-end}
.orbit-nav{display:flex; flex-direction:column; align-items:flex-end; gap:16px; list-style:none; margin:0; padding:0}
.orbit-nav li{margin:0; padding:0; display:flex; align-items:center; gap:14px}
/* mix-blend-mode:difference on this label was tried (and reverted) as a
   fix for its white text disappearing over white .grid-section content
   now that the panel is position:fixed and persists over the whole page.
   Tested directly with a minimal, isolated repro (no page complexity):
   blend-mode against a white background works correctly (renders black,
   as expected) in a flat DOM, but stops working the moment the blended
   element sits inside ANY ancestor with position:fixed OR an explicit
   z-index — both create a new stacking context per spec, and
   mix-blend-mode can only blend against content within its own stacking
   context. .orbit-panel needs both (fixed to stay pinned through scroll,
   z-index:60 to stay above page content), so this is a hard structural
   conflict, not a tunable bug — confirmed by testing, not assumed. See
   chat history for the repro and reasoning if revisiting this. */
/* Now an <a> (see index.html etc.) instead of a plain <span>, pointing at
   the same href as the sibling .orbit-planet icon anchor, tabindex:-1 +
   aria-hidden so it doesn't duplicate a stop in the tab order or the
   accessibility tree (the icon anchor already has the real aria-label
   and, where active, aria-current) — it exists purely so a mouse/touch
   click anywhere on the label text also navigates, not just the icon. */
.orbit-label{font-family:var(--font-serif); font-weight:400; font-size:14px;
  letter-spacing:.2em; line-height:1; color:#fff; white-space:nowrap; text-transform:uppercase;
  text-decoration:none; transition:color .2s linear}
/* .on-light is toggled per-label (not once for the whole panel) by
   site.js (syncOrbitContrast), based on whether a light .grid-section/
   .grid-intro is currently behind THAT label's own vertical position —
   see the JS comment for why this replaced mix-blend-mode. This is what
   lets labels above and below a scrolling navy/white boundary show
   different colors at the same time instead of the whole stack switching
   together. Desktop-only in practice: the JS removes this class from
   every label below 1250px, but the min-width guard here is
   belt-and-suspenders so it can never visually apply in the mobile band
   even if that toggle raced. */
@media (min-width:1251px){
  .orbit-label.on-light{color:var(--navy)}
}
/* Desktop side panel always shows the full name ("E-Commerce", "AI
   Integration"); the horizontal band below uses shorter forms instead so
   every label fits on one line at the band's sizing — see .orbit-label-*
   display swap in the max-width:1250px block. */
.orbit-label-short{display:none}
/* Circles bleed off the viewport edge, same as the hero planet renders */
.orbit-planet{position:relative; z-index:1; flex:none; width:84px; padding:0; border:0;
  background:none; -webkit-appearance:none; appearance:none; line-height:0; cursor:pointer;
  transform:translateX(30%);
  transition:transform .45s cubic-bezier(.22,1,.36,1)}
/* Earth/Mars/Venus's icons are pre-cropped circular PNGs (already square,
   transparent outside the circle), so this clip is a no-op for them.
   Saturn/Cortex use a plain rectangular hero still instead of a dedicated
   cropped icon, so aspect-ratio+object-fit+radius do the cropping here
   rather than needing a separately-prepared circular asset. */
.orbit-planet img{display:block; width:100%; aspect-ratio:1/1; object-fit:cover; border-radius:50%}
/* Venus render's shadow reads bottom-left; mirror so it falls toward the
   already-cropped right edge instead of sitting in the visible portion */
.orbit-planet[data-planet="venus"] img{transform:scaleX(-1)}
/* Saturn: the source render's ring span is much wider than the sphere
   itself. Cropping it to a circle like the other 4 icons forces a choice
   between cropping the rings off short or shrinking the whole render
   until the rings fit — shrinking the sphere along with them. Instead the
   image itself renders as a wider ellipse (border-radius:50% on a
   non-square box forms an ellipse automatically) so the sphere stays the
   same apparent size as Earth/Mars/Venus/Cortex while the rings extend
   into the extra width.
   Widening the *anchor* itself (an earlier version of this) grew the li's
   flex-row footprint, which dragged the label along with it — the label
   sits immediately left of the icon in flow, so a wider icon box pushed
   the label 42px further left than the other 4 rows' shared right edge,
   breaking label alignment. Instead the anchor stays the standard 84px
   (so the label's position is identical across all 5 rows, derived only
   from that constant width) and just the <img> inside is taken out of
   flow — position:absolute, pinned to the anchor's right edge, rendered
   at 150% width (126px) — so it can visually overflow left into the
   label's row without the layout ever knowing it's there. The explicit
   height replaces the one the anchor would otherwise get for free from
   its (now out-of-flow) img content.
   Desktop side-panel only — reset back to a plain in-flow circle in the
   max-width:1250px band below, where each item has a fixed-width slot
   with no room for an icon to overflow sideways without overlapping its
   neighbor.
   Active/focus rings are deliberately NOT overridden here — the generic
   .orbit-planet.is-active / :focus-visible rules below already draw the
   ring on the *anchor* (still a plain 84px square, per above), giving
   Saturn the same clean circular ring as the other 4 planets, sized to
   the planet body rather than stretched to the wider image. An earlier
   version moved the ring onto the <img> instead so it would enclose the
   full wide ellipse — that's what looked inconsistent with the other 4
   circles, and rings extending past a circular active-state boundary is
   already the expected look (it's exactly what the default, non-active
   state already does). */
.orbit-planet[data-planet="saturn"]{height:84px}
.orbit-planet[data-planet="saturn"] img{position:absolute; top:0; right:0; width:150%; aspect-ratio:3/2}
.orbit-planet:hover{transform:translateX(30%) scale(1.045)}
.orbit-planet:active{transform:translateX(30%) scale(.99)}
.orbit-planet:focus-visible{outline:2px solid var(--cyan); outline-offset:6px; border-radius:50%}
.orbit-planet.is-active{outline:2px solid var(--cyan); outline-offset:4px; border-radius:50%}
.orbit-planet.is-placeholder{aspect-ratio:1/1; border-radius:50%;
  background:radial-gradient(circle at 35% 30%, #2c4670, #0a1830); border:1px solid rgba(255,255,255,.25)}
@media (prefers-reduced-motion:reduce){
  .orbit-planet{transition:none} .orbit-planet:hover,.orbit-planet:active{transform:translateX(30%)}
}
@media (max-height:700px){
  .orbit-panel{top:calc(var(--nav-h) + 10px)}
  .orbit-nav{gap:9px}
  .orbit-planet{width:64px}
  /* Anchor width comes from the generic rule above (64px, same as every
     other planet) — the img's width:150% is relative, so it automatically
     rescales to 96px here without a separate override. Only the height
     (set in px, not derived) needs restating at this breakpoint's size. */
  .orbit-planet[data-planet="saturn"]{height:64px}
}
/* Panel-switch breakpoint: below this, the vertical right-docked stack
   becomes a compact horizontal band pinned above .copy instead — there's
   no width where a full 5-item stacked column of circles+labels can share
   the same row as centered hero copy without one dodging the other, and
   dodging via a dynamic side-inset on .col visibly pushed the hero copy
   off-center (rejected — .col must always be simply, symmetrically
   centered). 1250px was picked with a margin over where centered title/
   lede text naturally clears a right-docked 84px-circle/14px-label panel
   at this content length (verified independently by real glyph-rect
   measurement earlier in this file's history: clear by ~1180px; this
   breakpoint adds ~70px of headroom on top of that, and the p.lede
   max-width above removes the one branch-dependent variable — an
   unconstrained long first line on Cortex/Venus — that could have eaten
   into that margin). Below 1250px .col stays simply centered — see .col
   above, no side inset of any kind. Placed after the max-height:700px
   block above so its sizing always wins whenever both match. */
@media (max-width:1250px){
  /* Phone-tuned sizing (38px circle, 8.5px label) is the floor, held flat
     up to 760px wide. Above that it scales up continuously with viewport
     width, reaching ~1.65x (circle ~63px, label ~14px — close to the
     vertical panel's own 84px/14px pairing) right at the 1250px edge of
     this band, so a genuinely desktop-width browser window doesn't render
     the same cramped size tuned for a ~390px phone. Circle width and label
     font-size are both computed FROM this one factor rather than set as
     independent fixed px, so a second, differently-sized tier isn't needed
     to cover the range — one continuous formula instead of tier edges to
     keep in sync. */
  :root{--band-scale: clamp(1, calc(100vw / 760px), 1.65)}
  /* This band is now fixed to the viewport top (see the base .orbit-panel
     rule), so page content scrolls directly underneath it rather than
     past it once. Give it its own backdrop so that scrolling text/planet
     icons don't read as content being sliced by a hard edge:
     - background: a navy tint (matches --navy) so anything showing
       through the blur still reads as "under a dark panel", not just
       blurry.
     - backdrop-filter: blurs whatever's scrolling underneath.
     - mask-image: fades the blur+tint out toward the bottom of the box,
       rather than either effect stopping on a hard line — the box is
       taller than its own nav content (padding-bottom) specifically to
       leave room for this fade to happen gradually instead of clipping
       right at the icons' bottom edge. Desktop's vertical side panel
       intentionally skips all of this — it doesn't sit over scrolling
       content the same way a full-width top band does. */
  .orbit-panel{top:0; left:0; right:0; align-items:center;
    padding:calc(var(--nav-h) - 24px) 0 28px;
    background:linear-gradient(to bottom, rgba(4,16,31,.88) 0%, rgba(4,16,31,.88) 62%, rgba(4,16,31,0) 100%);
    -webkit-backdrop-filter:blur(12px); backdrop-filter:blur(12px);
    -webkit-mask-image:linear-gradient(to bottom, #000 0%, #000 62%, transparent 100%);
    mask-image:linear-gradient(to bottom, #000 0%, #000 62%, transparent 100%)}
  .orbit-nav{width:100%; flex-direction:row; flex-wrap:wrap; justify-content:center;
    align-items:flex-start; gap:calc(10px * var(--band-scale)) calc(12px * var(--band-scale));
    padding:0 calc(16px * var(--band-scale))}
  .orbit-nav li{flex-direction:column; align-items:center;
    gap:calc(4px * var(--band-scale)); width:calc(58px * var(--band-scale))}
  /* Circle above its label in this layout (order:-1 beats the button's
     default order:0, without touching DOM order — which the desktop side
     panel above 1250px still relies on for its label-then-circle row). */
  .orbit-planet{width:calc(38px * var(--band-scale)); transform:none; order:-1}
  .orbit-planet:hover{transform:scale(1.045)}
  .orbit-planet:active{transform:scale(.99)}
  /* Saturn's wide-ellipse treatment is desktop-panel-only (see the base
     rule above) — this band's li has a fixed width (58px * --band-scale)
     sized for a circle, with no slack to grow sideways without overlapping
     the neighboring wrapped item, so keep it circular here like the rest:
     reset the anchor's fixed height and the img's out-of-flow overflow
     treatment back to the same in-flow, self-sized circle every other
     planet uses at this breakpoint. */
  .orbit-planet[data-planet="saturn"]{height:auto}
  .orbit-planet[data-planet="saturn"] img{position:static; width:100%; aspect-ratio:1/1}
  /* Band-only short forms ("E-Comm", "AI") replace the desktop panel's
     full names so every label fits on one line at every width in this
     range — verified by the same scale-invariance argument --band-scale
     already relies on elsewhere: label and container both scale by the
     identical factor, so if a label fits at the 390px floor it fits at
     every larger size in the band too. "E-Comm" is the same length class
     as "Social" (already confirmed single-line here); "AI" is shorter
     than "Home". With no label ever wrapping, the fixed-height label box
     from earlier rounds is no longer needed — a single-line label is the
     same rendered height for all 5 items on its own, so the row stays
     aligned without reserving extra space for a second line that no
     longer happens. white-space stays at the base rule's nowrap (not
     overridden here) as a hard guarantee against a wrap ever reappearing. */
  .orbit-label{font-size:calc(8.5px * var(--band-scale)); letter-spacing:.03em}
  .orbit-label-full{display:none}
  .orbit-label-short{display:inline}
  .copy{top:var(--orbit-clear, calc(76 * var(--u)))}
}

/* ============ TILT (mouse-tracked 3D tilt effect) ============ */
/* Ported from a React TiltCard component (Grad Gig) — see /assets/tilt.js
   for the rotateX/rotateY + sheen-position logic; this is just the
   transform surface and sheen overlay it drives via inline style and CSS
   custom properties. .tilt-target is applied directly to an <img> (an
   img can't have children), so tilt.js injects .tilt-sheen as a sibling
   into the img's parent instead of a child — this only lines up because
   that parent (e.g. .team-photo-lp, light-theme.css) is already
   position:relative and exactly the same box as the img itself.
   z-index:2 matches .role-tag-lp so the sheen paints above
   .team-photo-lp's own ::after gradient (position:absolute with no
   z-index, i.e. z-index:auto — an explicit positive z-index always
   stacks above that regardless of DOM order), instead of getting hidden
   underneath it. */
.tilt-target{position:relative; transform-style:preserve-3d}
.tilt-sheen{position:absolute; inset:0; z-index:2; border-radius:inherit;
  pointer-events:none; opacity:var(--sheen-opacity, 0);
  background:radial-gradient(circle at var(--sheen-x, 50%) var(--sheen-y, 50%), rgba(255,255,255,.25), transparent 55%);
  transition:opacity .2s ease-out}
