/* =========================================================================
   Sidus Strategic Solutions — visual system  (V0.5.1 "Constellation, night")
   Deep-navy ground · light node accent · editorial-luxe.
   The Constellation direction (brand pack, Further 01) ON ITS OWN GROUND.

   V0.5 used Constellation's four hexes INVERTED, to keep a light build and ask
   "which direction?" without re-asking "light or dark?". V0.5.1 stops inverting:
   this is the direction exactly as the pack card ships it — #0B1120 as the
   ground, #EAF2FF as the points of light. Structure, copy, type ramp and motion
   timing are still untouched from V0.4.1, so the family stays comparable.

   Two deltas from V0.5, and only two:

     1. The world is dark, so every inversion rule V0.4 wrote runs BACKWARDS —
        see "the third inversion" below. This is not a value flip; roughly a
        dozen rules change kind, not just number.

     2. The hero is the MARK, full stop. V0.5's hero carried the mark plus one
        faint outer frame for scale. Here there is no outer frame: one diamond,
        its axes, five nodes, two loose stars — the pack's drawing, enlarged and
        nothing else. On a dark ground it does not need the extra scaffolding to
        hold the frame; the points carry it on their own.

   V0.5.2 is this build with a smaller hero. Everything else there is identical,
   which is the point — it isolates hero SCALE the way V0.3.1/.2 did.

   --- What Constellation is ---
   From the brand pack: "points of light, connected — one system from separate
   parts." The mark is a diamond OUTLINE with its two axes drawn through it, a
   round node at each vertex, a larger node at the centre, and two loose stars
   off-axis. Two things follow, and both are load-bearing here:

     1. The diamond survives as the FRAME, not as the atom. Sidus DNA is still a
        diamond (Sidus / Naledi = "star"), but in this direction the repeated
        small unit is a round NODE. So every 5-7px diamond speck this build
        inherited — eyebrow bullets, rule pips, proof separators, step markers —
        is a circle here. That swap is the direction, not a detail: leave the
        specks as diamonds and the page is still wearing the old mark in
        miniature while the logo wears a new one.

     2. Points are CONNECTED. The line through a node is as much the mark as the
        node is, which is why the hero draws its axes full width and the ambient
        canvas keeps its linking threads.

   --- The palette, used the right way up ---
   Constellation ships four hexes: #0B1120 · #4E6288 · #9FB6D8 · #EAF2FF, and the
   card puts the dark one on the floor. So does this build. #0B1120 is the ground
   as shipped, #9FB6D8 is the accent, #EAF2FF is the emphatic end, and #4E6288 —
   which was the ACCENT on the light build — demotes to the faint end, because on
   a dark ground it is the value nearest the floor. Same four hexes, opposite jobs.

   --- The third inversion, running backwards ---
   V0.4's header note said paper does not emit light, so every glow became a cast
   shadow. Black does emit, so they all come back, and each one is a change of
   KIND rather than of number — don't try to "simplify" any of them back:
     · --glow-accent is a real halo again, not `none`. Small labels at 12px have
       no hue to spend on a dark ground and flatten into the surrounding greys
       without it. On paper the same halo read as smudge; here it reads as light.
     · --shadow-card / --shadow-lift stop being cast shadows. A dark card on a
       dark ground cannot be lifted by a shadow — there is nothing darker to cast
       onto — so elevation is carried by a rising SURFACE VALUE instead, which is
       why --surface-2 is a real step up here and was pure white on the light build.
     · The hero vignettes DARKEN to give the headline contrast; on paper they
       lightened to do the same job.
     · .grain goes back to `overlay` from `multiply`. Multiply on black does
       nothing at all: there is no light for the tooth to take away.

   --- Still true, do not "simplify" away ---
     · HUE does the separating. A neutral light accent on black lands on the same
       value as the body text and the page collapses into grey mush — the exact
       mirror of the light build's problem. Constellation's blue cast does that
       job, which is why the neutrals stay cool.
     · Accents are METAL, and on a dark ground the trick flips back to the DARK
       band: a shadow running through an otherwise light ramp is what separates
       polished metal from flat silver. See --metal.
   ========================================================================= */

/* ---- Self-hosted variable fonts (offline, no CDN) ---- */
@font-face {
  font-family: "Fraunces";
  src: url("fonts/fraunces.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("fonts/fraunces-italic.woff2") format("woff2");
  font-weight: 100 900; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("fonts/hanken.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}

/* ---- Tokens ---- */
:root {
  /* Token RENAME from V0.5, deliberate: --paper/--paper-2 would now lie. The
     ground is not paper here, it is Constellation's own #0B1120, and the band
     RISES above it rather than sinking below (the light build's band sank —
     on a dark ground the only direction to move is up). */
  --ink:        #0B1120;   /* page ground — Constellation's darkest, as shipped */
  --ink-2:      #101830;   /* alternating band — rises ABOVE the ground */
  --surface:    #141D33;   /* cards, panels */
  --surface-2:  #1B2642;   /* raised / hover — a REAL step up. On the light build
                              this was pure white and the hover lifted by shadow
                              instead; here there is nothing darker to cast onto,
                              so value does the lifting. */
  /* Alphas track V0.5's (.15/.22/.38) but land differently: a light hairline on a
     dark ground reads heavier than a dark one on paper at equal alpha, so these
     come DOWN rather than being carried across unchanged. */
  --hair:         rgba(159, 182, 216, 0.12);
  --hair-2:       rgba(159, 182, 216, 0.18);
  --hair-accent:  rgba(159, 182, 216, 0.32);

  /* neutrals stay cool, for the same reason every build in this family does: to
     keep a gap the accent can live in. Warm greys would close it. */
  --text:       #EDF2FB;   /* the pack card's own foreground */
  --body:       #B7C6E0;
  /* Same AA parity rule the light build was held to — clear 4.5:1 on EVERY ground
     the page puts it on, which here is four, not three (--surface-2 is a real
     colour now). Measured: ink 6.00, ink-2 5.60, surface 5.34, surface-2 4.77.
     NOT the card's own #7E8AA2: that measures 4.31 on --surface-2 and fails. The
     hover surface is the tightest of the four and is what pins this value. */
  --muted:      #8492AC;

  --accent:        #9FB6D8;  /* Constellation's light-mid, as shipped — 9.11:1 on ink */
  --accent-strong: #EAF2FF;  /* the emphatic end — BRIGHTEST here, darkest on paper */
  --accent-soft:   #4E6288;  /* the pack's mid, demoted to the faint end — decorative */
  --accent-wash:   rgba(159, 182, 216, 0.10);
  --accent-rgb:    159, 182, 216;

  /* Small labels (eyebrows, chapter indices, card numbers). The light build deleted
     this halo outright, because a dark blue label separates from muted body text on
     paper by hue AND value at once. That is a paper-only luxury: at 12px on a dark
     ground the label has no hue left to spend and flattens into the greys, so the
     halo comes back rather than staying `none`. */
  --accent-label:  #C9DAF3;
  --glow-accent:   0 0 14px rgba(159, 182, 216, 0.32);

  /* The button metal ramp — light, with a DARK shadow band at 62%. The trick is
     the mirror of the light build's: there the metal was dark and a specular
     streak sold it; here the metal is light and the shadow does.
     The label is #0B1120, so it has to clear 4.5:1 against the DARKEST point of
     its own background — the exact opposite constraint to the light build, where
     the brightest point was the binding one. The band stops at #6B82AD and no
     darker (4.86:1). The pack's own #4E6288 was the first choice and had to be
     rejected: it measures 3.07:1 under the label. */
  --metal: linear-gradient(180deg, #C6D7EE 0%, #EAF2FF 34%, #6B82AD 62%, #B4C8E6 100%);

  /* Elevation stops being a cast shadow and becomes a GLOW. A shadow under a dark
     card on a dark ground is invisible — there is nothing darker to cast — so the
     card is separated by a cool bloom around it plus the surface step above. */
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.30), 0 8px 24px rgba(0, 0, 0, 0.26);
  --shadow-lift: 0 2px 6px rgba(0, 0, 0, 0.34), 0 16px 40px rgba(11, 17, 32, 0.55),
                 0 0 32px -8px rgba(159, 182, 216, 0.16);

  --serif: "Fraunces", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* --- Type ramp. One size per role, one weight per role. Every serif display
         element picks from this list — nothing sets an ad-hoc size or weight. --- */
  --fs-display:   clamp(2.3rem, 5.2vw, 3.85rem);   /* hero headline only */
  --fs-promise:   clamp(1.32rem, 2.4vw, 1.82rem);  /* hero promise line */
  --fs-statement: clamp(2rem, 3.9vw, 3rem);        /* h2 · gap quote · about statement */
  --fs-vm:        clamp(1.15rem, 2vw, 1.5rem);     /* vision / mission cards */
  --fs-h3:        clamp(1.2rem, 2vw, 1.4rem);      /* card + step headings */
  --fs-lead:      clamp(1.05rem, 1.6vw, 1.22rem);
  --fs-body:      0.95rem;
  --fs-micro:     0.72rem;                          /* eyebrows, labels, step nums */

  --w-display: 620;   /* hero only — deliberately the boldest thing on the page */
  --w-head:    500;   /* every other serif display element */
  --w-body:    400;

  --wrap: 1160px;
  --gap: clamp(1.5rem, 4vw, 3rem);
  --section-y: clamp(4.75rem, 10vw, 8.5rem);
  --radius: 14px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---- Reset / base ---- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.7;
  color: var(--body);
  background: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
::selection { background: rgba(var(--accent-rgb), 0.18); color: var(--text); }

:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 3px; border-radius: 4px; }

/* ---- Filmic grain (fixed, whole page) ----
   Back to `overlay`, which is the dark-ground blend. `multiply` — correct on
   paper, where tooth takes light away — does nothing at all here: there is no
   light in #0B1120 to subtract. Opacity rises with it, since overlay on black
   registers far more softly than multiply on white did. */
.grain {
  position: fixed; inset: 0; z-index: 60; pointer-events: none;
  opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
}

/* ---- Typography ---- */
h1, h2, h3, h4 {
  font-family: var(--serif); color: var(--text);
  font-weight: var(--w-head); line-height: 1.08; letter-spacing: -0.015em;
  text-wrap: balance; margin: 0;
}
h2 { font-size: var(--fs-statement); }
h3 { font-size: var(--fs-h3); letter-spacing: -0.01em; }
p { margin: 0; }
em { font-style: italic; }

.eyebrow {
  font-family: var(--sans); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent-label);
  text-shadow: var(--glow-accent);
  display: inline-flex; align-items: center; gap: 0.6rem;
}
/* A NODE, not a diamond speck — see rule 1 in the header note. Same 6px footprint
   and the same cast shadow; only the silhouette changes. Every other small mark on
   the page follows this one. */
.eyebrow::before {
  content: ""; width: 6px; height: 6px; background: var(--accent);
  border-radius: 50%; box-shadow: 0 1px 3px rgba(var(--accent-rgb), 0.35);
}

/* chapter kicker: faint serif index + eyebrow */
.kicker { display: flex; align-items: baseline; gap: 0.9rem; }
.kicker__idx {
  font-family: var(--serif); font-size: 0.95rem; font-weight: var(--w-head);
  color: var(--accent-label); text-shadow: var(--glow-accent);
  font-variant-numeric: tabular-nums; letter-spacing: 0.02em;
  position: relative; padding-right: 0.9rem;
}
.kicker__idx::after {
  content: ""; position: absolute; right: 0; top: 50%; width: 0.5rem; height: 1px;
  background: var(--hair-accent);
}
.kicker--center { justify-content: center; }

.lead { color: var(--body); font-size: var(--fs-lead); line-height: 1.65; }
.measure { max-width: 62ch; }

/* ---- Layout ---- */
.wrap { width: min(var(--wrap), 100% - 2.5rem); margin-inline: auto; }
.section { padding-block: var(--section-y); position: relative; scroll-margin-top: 92px; }
.section--alt { background: var(--ink-2); }
.section__head { max-width: 64ch; margin-bottom: clamp(2.4rem, 5vw, 3.6rem); }
.section__head h2 { margin-top: 1rem; }
.section__head .lead { margin-top: 1.1rem; max-width: 58ch; }

/* Divider with a node. This is now the mark's own cross-axis in miniature — a
   line running through a lit point — which is why it reads as Constellation
   rather than as a generic ornament. */
.starrule { display: flex; align-items: center; gap: 1rem; color: var(--hair-accent); }
.starrule::before, .starrule::after {
  content: ""; height: 1px; flex: 1;
  background: linear-gradient(90deg, transparent, var(--hair-2), transparent);
}
.starrule i {
  width: 7px; height: 7px; background: var(--accent); border-radius: 50%; flex: none;
  box-shadow: 0 2px 6px rgba(var(--accent-rgb), 0.32);
}

/* ---- Navigation ---- */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 70;
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem clamp(1.25rem, 4vw, 2.5rem);
  transition: background 0.4s var(--ease), padding 0.4s var(--ease), border-color 0.4s var(--ease);
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  background: rgba(11, 17, 32, 0.85);   /* --ink, translucent */
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom-color: var(--hair);
  padding-block: 0.65rem;
}
/* ---- The lockup ----
   V0.4.1 set the logo as a raster PNG (her supplied mark + wordmark, flattened).
   Constellation ships a redrawn VECTOR mark, so the lockup is rebuilt as inline
   SVG + live text: it scales without a 2x asset, it inherits --text and --accent
   instead of being baked, and the nav's shrink-on-scroll becomes a font-size
   change rather than a resample. The proportions are the brand pack's own
   (mark : wordmark ≈ 2.4 : 1, tagline tracked to 0.26em).

   The tagline holds a 8px floor rather than scaling with the mark. At the brand
   pack's ratio it would land near 5px in the nav — the PNG it replaces was no
   better, but "no worse than the thing we're fixing" isn't the bar. */
.nav__logo { display: inline-flex; align-items: center; gap: 0.62rem; }
.lockup__mark {
  width: 34px; height: 34px; flex: none; display: block; overflow: visible;
  transition: width 0.4s var(--ease), height 0.4s var(--ease);
}
.lockup__text { display: flex; flex-direction: column; gap: 0.14rem; line-height: 1; }
.lockup__name {
  font-family: var(--sans); font-size: 0.98rem; font-weight: 600;
  letter-spacing: 0.16em; color: var(--text);
  transition: font-size 0.4s var(--ease);
}
.lockup__tag {
  font-family: var(--sans); font-size: 0.5rem; font-weight: 500;
  letter-spacing: 0.26em; text-transform: uppercase; color: var(--accent);
}
/* The PNG lockup this replaces was one image and could not wrap. Live text can,
   and does: at 390px the nav squeezes the tagline onto two lines and the lockup
   stops looking like a logo. Both lines are pinned. */
.lockup__name, .lockup__tag { white-space: nowrap; }
.nav.is-stuck .lockup__mark { width: 29px; height: 29px; }
.nav.is-stuck .lockup__name { font-size: 0.88rem; }

/* The mark's own parts, shared by every instance (nav, footer, hero is separate).
   Strokes carry the frame, fills carry the light — inverted to ink on paper, so
   the "points of light" are the DARKEST things in the mark rather than the
   brightest. Same inversion the whole build runs on. */
.lockup__mark .mk-frame { fill: none; stroke: var(--accent); stroke-width: 1; opacity: 0.55; }
.lockup__mark .mk-node  { fill: var(--text); }
.lockup__mark .mk-star  { fill: var(--accent); opacity: 0.75; }
.nav__links { display: flex; align-items: center; gap: clamp(1.25rem, 2.4vw, 2.2rem); }
.nav__links a.link { font-size: 0.9rem; color: var(--body); position: relative; transition: color 0.25s var(--ease); }
.nav__links a.link::after {
  content: ""; position: absolute; left: 0; bottom: -6px; height: 1px; width: 0;
  background: var(--accent); transition: width 0.3s var(--ease);
}
.nav__links a.link:hover { color: var(--text); }
.nav__links a.link:hover::after { width: 100%; }
.nav__links a.link.is-active { color: var(--text); }
.nav__links a.link.is-active::after { width: 100%; background: var(--accent); opacity: 0.8; }

@media (max-width: 720px) { .nav__links .link { display: none; } }

/* ---- Buttons ---- */
.btn {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-family: var(--sans); font-size: 0.92rem; font-weight: 600;
  letter-spacing: 0.01em; padding: 0.8rem 1.4rem; border-radius: 999px;
  cursor: pointer; border: 1px solid transparent;
  transition: transform 0.25s var(--ease), background 0.25s var(--ease),
              border-color 0.25s var(--ease), color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.btn svg { width: 15px; height: 15px; transition: transform 0.25s var(--ease); }
/* the primary button is the LIGHT metal on a dark ground — the inverse of V0.5,
   where it was dark metal on paper. Same object, same ramp logic, opposite ground,
   and the label inverts with it: dark type on light metal. The glow is allowed to
   be much stronger than the light build's shadow, because on black it reads as the
   button emitting rather than as dirt around it.
   Class name kept as .btn--silver so the markup stays identical across versions. */
.btn--silver {
  background: var(--metal);
  color: #0B1120; box-shadow: 0 8px 30px -12px rgba(var(--accent-rgb), 0.60);
}
.btn--silver:hover { transform: translateY(-2px); box-shadow: 0 14px 38px -12px rgba(var(--accent-rgb), 0.85); }
.btn--silver:hover svg { transform: translateX(3px); }
.btn--ghost { border-color: var(--hair-2); color: var(--text); background: transparent; }
.btn--ghost:hover { border-color: var(--accent); color: var(--accent-strong); transform: translateY(-2px); }

/* ============================ HERO ============================ */
.hero {
  position: relative; min-height: 100svh;
  display: flex; align-items: center;
  padding-block: 7rem 6rem; overflow: hidden;
}
#stars { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; }
/* Inherited from V0.4.1 unchanged (only the accent inside it is Constellation's):
   base V0.3's original THREE-layer rig, inverted, where V0.4 carries V0.3.2's six.
   No dedicated headline vignette here and none needed: V0.3.2 added one to darken
   black behind white type, but on paper the ground is already the bright end, so
   ink type has its contrast for free. This is the single biggest reason this hero
   reads calm rather than lit — and keeping it is what makes V0.5 a fair test of
   the DIRECTION rather than of a new hero. */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    /* mark halo — a cool bloom pooling around the lit mark. Same position as the
       light build's, but it now ADDS light instead of tinting a white ground, so
       it carries roughly double the alpha to register at all. */
    radial-gradient(48% 55% at 78% 30%, rgba(var(--accent-rgb), 0.13), transparent 60%),
    /* faint lower-left fill so the frame isn't one-sided */
    radial-gradient(60% 50% at 12% 108%, rgba(var(--accent-rgb), 0.07), transparent 60%),
    /* centering wash. On paper this LIGHTENED toward white to seat the headline;
       on a dark ground the same job is done by DARKENING toward the ground, so
       the wash runs to transparent-black rather than to white. */
    radial-gradient(100% 100% at 30% 55%, rgba(11, 17, 32, 0.00), var(--ink) 80%);
}
.hero .wrap { position: relative; z-index: 3; }
.hero__inner { max-width: 48rem; }
.hero__eyebrow { margin-bottom: 1.6rem; }

/* The headline — the boldest, clearest thing on the page, by request. */
.hero__title {
  font-size: var(--fs-display);
  font-weight: var(--w-display);
  line-height: 1.03; letter-spacing: -0.028em;
  max-width: 20ch;
}
.hero__title span { display: block; }

.hero__rule { display: flex; align-items: center; gap: 0.8rem; margin-top: 1.7rem; max-width: 20rem; }
.hero__rule i {
  width: 6px; height: 6px; background: var(--accent); border-radius: 50%; flex: none;
  box-shadow: 0 1px 4px rgba(var(--accent-rgb), 0.35);
}
.hero__rule::after {
  content: ""; height: 1px; flex: 1;
  background: linear-gradient(90deg, var(--hair-accent), transparent);
}

/* The promise line kept from V0.1, demoted below the tagline but still large. */
.hero__promise {
  margin-top: 1.1rem; max-width: 30ch;
  font-family: var(--serif); font-style: italic; font-weight: var(--w-body);
  font-size: var(--fs-promise); line-height: 1.3;
  color: var(--accent);
}
.hero__promise em { color: var(--accent-strong); font-style: italic; }

.hero__sub {
  margin-top: 1.5rem; max-width: 50ch;
  font-size: var(--fs-lead); line-height: 1.62; color: var(--body);
}
.hero__cta { margin-top: 2.4rem; display: flex; flex-wrap: wrap; gap: 1rem; }

/* proof strip */
.hero__proof {
  position: absolute; left: 0; right: 0; bottom: 2.4rem; z-index: 3;
  width: min(var(--wrap), 100% - 2.5rem); margin-inline: auto;
  display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap;
  color: var(--muted); font-size: 0.74rem; letter-spacing: 0.14em; text-transform: uppercase;
}
.hero__proof i { width: 5px; height: 5px; background: var(--accent); border-radius: 50%; opacity: 0.7; }
.hero__scroll {
  position: absolute; right: clamp(1.25rem, 4vw, 2.5rem); bottom: 2.1rem; z-index: 3;
  color: var(--muted); font-size: 0.7rem; letter-spacing: 0.2em; text-transform: uppercase;
  display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
}
.hero__scroll span { width: 1px; height: 42px; background: linear-gradient(var(--accent), transparent); }

/* ---------------- Diamond constellation (hero focal) ---------------- */
.facets {
  position: absolute; z-index: 2; pointer-events: none;
  right: -2vw; top: 50%;
  transform: translate(0, calc(-50% + var(--py, 0px)));
  will-change: transform;
  width: clamp(430px, 45vw, 700px); aspect-ratio: 1;
}
.facets svg { position: relative; z-index: 1; width: 100%; height: 100%; overflow: visible; }

/* No .jewel-aura, no .facets__stage entrance, no ring draw-in and no .fx-spark
   here — those are V0.3.1/.2 additions and this build is base V0.3. The jewel
   simply IS, breathing on its ring clocks; it never announces itself on load.
   (The markup has no pathLength="1" either, so nothing is left half-drawn.) */

/* Raking sheen — a soft light source turning slowly behind the mark. On paper this
   had to become a raking SHADOW; on a dark ground it is a light source again, as
   originally written. Still the one thing here allowed to rotate — it is a formless
   blur, not a diamond, so spinning it costs nothing. Alphas roughly double: an
   additive bloom on #0B1120 registers far less than a tint on white did. */
.facets::before {
  content: ""; position: absolute; inset: 8%; z-index: 0;
  border-radius: 50%; pointer-events: none;
  background: conic-gradient(from 0deg,
    transparent 0deg,
    rgba(var(--accent-rgb), 0.14) 38deg,
    transparent 96deg,
    transparent 200deg,
    rgba(var(--accent-rgb), 0.09) 250deg,
    transparent 312deg);
  filter: blur(26px);
  animation: sheen-turn 26s linear infinite;
}
@keyframes sheen-turn { to { transform: rotate(360deg); } }

/* The core scales about its OWN centre; the frames breathe about the shared centre
   of the viewBox. Two different transform-boxes — don't collapse them into one. */
.fx { transform-box: fill-box; transform-origin: center; }
.ring { transform-box: view-box; transform-origin: 320px 320px; }

/* --- Frame: the diamond outline and the two axes drawn through it. ---
   ONE frame here, where V0.5 had two and V0.4.1 had four. V0.5's outer echo was
   scaffolding: on paper the mark's own strokes are dark hairlines that thin out at
   hero scale, and the echo gave the drawing something to hold. Lit points on a dark
   ground don't need it — they carry their own presence — so this is the pack's mark
   and nothing else. Stroke alpha rises to compensate for the frame it lost. */
.fx-frame { fill: none; stroke: rgba(var(--accent-rgb), 0.55); stroke-width: 1.4; }

/* The axes are as much the mark as the nodes are — "points of light, CONNECTED".
   They fade toward the vertices so the crossing at the centre stays the loudest
   thing in the drawing. */
.fx-axis { stroke: url(#axis); stroke-width: 1.3; fill: none; }

/* a soft bloom behind the whole mark. On paper this was a cast shadow giving the
   dark mark WEIGHT; here it inverts to what the pack card actually shows — the
   mark glowing off the ground rather than pressing into it. */
.fx-halo {
  fill: rgba(var(--accent-rgb), 0.10); stroke: none;
  filter: blur(30px);
}

/* Nodes are round, and they are the BRIGHTEST things in the drawing — which is
   how the pack card draws them (#EAF2FF on #0B1120). The light build had to invert
   that to deepest ink; this one doesn't. The drop-shadow becomes a real halo. */
.fx-node { fill: var(--accent-strong); filter: drop-shadow(0 0 6px rgba(var(--accent-rgb), 0.55)); }
/* The loose stars are the SUPPORTING points and must never compete with the mark's
   own five. Held back by fill AND by a shallower twinkle (see fx-twinkle-soft); no
   static opacity here, because the twinkle animates that property and would simply
   overwrite it. */
.fx-star { fill: var(--accent); }
.fx-core {
  fill: url(#metal);   /* not a flat fill — the ramp is what makes it metal */
  filter: drop-shadow(0 0 18px rgba(var(--accent-rgb), 0.45));
}

/* --- Travelling stars (the orbiters, reclaimed from V0.1) ---
   V0.4.1 needed a two-element rig here: an outer <g> carrying the orbit and an
   inner .orbiter__upright cancelling it, because a DIAMOND satellite that rolls
   as it travels flattens into a tilted rectangle. Constellation's loose stars are
   circles, and a circle is rotationally symmetric — so the counter-rotation has
   nothing left to cancel and the inner group is gone from both the markup and
   here. Deleted rather than left inert: an unexplained no-op is worse than the
   history it preserves. (If a future direction puts diamonds back on these
   orbits, the cancel-group has to come back with them.) */
.orbiter { transform-box: view-box; transform-origin: 320px 320px; }
@keyframes orbit-run { to { transform: rotate(360deg); } }

.orbiter--a { animation: orbit-run 44s linear infinite; }
.orbiter--b { animation: orbit-run 66s linear infinite reverse; }
.orbiter--c { animation: orbit-run 88s linear infinite; }

/* --- motion. The frames must NOT rotate. Constellation's diamond is very nearly
       square (the mark is 72 tall by 68 wide, and the hero holds that ratio), and
       a near-square is exactly the shape that reads as a DIAMOND at 45° and as a
       tilted box at any other angle — so rotation is even less survivable here
       than it was for V0.4.1's tall jewel. Instead each frame breathes about the
       shared centre on its own non-harmonic clock: the mark pulses like a field
       of light and the silhouette stays a diamond at every frame. --- */
@keyframes ring-breathe {
  0%, 100% { transform: scale(1);     opacity: 0.72; }
  50%      { transform: scale(1.045); opacity: 1; }
}
@keyframes fx-twinkle {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}
/* the supporting points' swing — same clock, shallower and dimmer */
@keyframes fx-twinkle-soft {
  0%, 100% { opacity: 0.22; }
  50%      { opacity: 0.62; }
}
@keyframes fx-pulse {
  0%, 100% { opacity: 0.7; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.14); }
}
@keyframes fx-drift {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-12px); }
}

.facets svg { animation: fx-drift 28s ease-in-out infinite; }

/* durations stay deliberately non-harmonic — the two frames never resync, so the
   pulse never reads as a repeating sonar ping. Same clocks V0.4.1 gave its
   equivalent rings, so the hero breathes at exactly the tempo it did before. */
/* One frame, so one clock. The non-harmonic pairing existed to stop two frames
   resyncing into a sonar ping; with the outer frame gone there is nothing to beat
   against, and .ring--outer is deleted rather than left pointing at absent markup. */
.ring--mark { animation: ring-breathe 11.5s ease-in-out infinite; animation-delay: -2.2s; }

.fx-node, .fx-star { animation: fx-twinkle 6s ease-in-out infinite; }
/* order-dependent: this only overrides the NAME, inheriting the clock above.
   Keep it after that rule — the selectors tie on specificity. */
.fx-star { animation-name: fx-twinkle-soft; }
.nd--a { animation-delay: -0.4s } .nd--b { animation-delay: -1.9s }
.nd--c { animation-delay: -3.1s } .nd--d { animation-delay: -4.6s }
.nd--e { animation-delay: -2.3s } .nd--f { animation-delay: -5.2s }
.nd--g { animation-delay: -1.1s } .nd--h { animation-delay: -3.8s }
.nd--i { animation-delay: -0.9s } .nd--j { animation-delay: -4.1s }
.nd--k { animation-delay: -2.7s } .nd--l { animation-delay: -5.6s }
.nd--m { animation-delay: -1.5s } .nd--n { animation-delay: -3.4s }
.nd--o { animation-delay: -5.9s } .nd--p { animation-delay: -2.1s }

.fx-core { animation: fx-pulse 7s ease-in-out infinite; }

/* hero line-reveal on load (only hidden when JS is present to reveal it) */
.js .reveal-line { opacity: 0; transform: translateY(18px); }
.js body.is-ready .reveal-line {
  animation: line-in 0.9s var(--ease) forwards;
}
.hero__eyebrow.reveal-line { animation-delay: 0.05s; }
.hero__title .reveal-line:nth-child(1) { animation-delay: 0.16s; }
.hero__title .reveal-line:nth-child(2) { animation-delay: 0.28s; }
.hero__rule.reveal-line { animation-delay: 0.40s; }
.hero__promise.reveal-line { animation-delay: 0.48s; }
.hero__sub.reveal-line { animation-delay: 0.60s; }
.hero__cta.reveal-line { animation-delay: 0.72s; }
.hero__proof.reveal-line { animation-delay: 0.88s; }
/* No filter on the hero lines: a lingering filter layer (even blur(0)) disables
   subpixel AA and softens the text vs. the other versions. Rise + fade only.
   This matters MORE on paper than it did on black — dark-on-light is exactly
   where subpixel AA does its most visible work. */
@keyframes line-in { to { opacity: 1; transform: none; } }

/* ---- 01 · About / two-column ---- */
.about__grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
.about__statement { margin-top: 1.3rem; line-height: 1.22; }
.about__statement em { color: var(--accent); }
.about__body .lead { margin-bottom: 1.1rem; }
.about__body p + p { margin-top: 1.1rem; }

/* ============================ 02 · THE GAP ============================ */
.gap { text-align: center; overflow: hidden; }
.gap .kicker { margin-bottom: 2rem; }
.gap__quote {
  margin: 0 auto; max-width: 22ch; font-family: var(--serif);
  font-size: var(--fs-statement); line-height: 1.18; color: var(--text);
  font-weight: var(--w-head); letter-spacing: -0.015em;
}
.gap__quote em { color: var(--accent); }
.gap__resolve {
  margin: 1.8rem auto 0; max-width: 40ch; color: var(--body);
  font-size: var(--fs-lead);
}
.gap__rule { max-width: 220px; margin: 2.8rem auto 0; }

/* ---- Vision / Mission (north star band) ---- */
.northstar__rule { max-width: 260px; margin: 0 auto clamp(2.6rem, 5vw, 3.6rem); }
.vm { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; }
.vm__card {
  background: var(--surface); border: 1px solid var(--hair);
  border-radius: var(--radius); padding: clamp(1.8rem, 3vw, 2.6rem);
  position: relative; overflow: hidden;
  box-shadow: var(--shadow-card);
}
.vm__card::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 2px;
  background: linear-gradient(var(--accent), transparent);
}
.vm__card .eyebrow { margin-bottom: 1rem; }
.vm__text {
  font-family: var(--serif); font-size: var(--fs-vm);
  line-height: 1.35; color: var(--text); font-weight: var(--w-head);
  letter-spacing: -0.01em;
}

/* ---- Values ---- */
.values { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; }
.value { padding: 1.75rem 0 0; border-top: 1px solid var(--hair-2); position: relative; }
.value::before {
  content: ""; position: absolute; top: -1px; left: 0; width: 42px; height: 2px;
  background: var(--accent); transition: width 0.35s var(--ease);
}
.value:hover::before { width: 100%; }
.value h3 { margin-bottom: 0.6rem; }
.value p { font-size: var(--fs-body); color: var(--muted); }

/* ---- Services / The S ---- */
.svc { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.25rem; }
.svc__card {
  background: var(--surface); border: 1px solid var(--hair);
  border-radius: var(--radius); padding: clamp(1.8rem, 2.8vw, 2.3rem);
  min-height: 15rem;
  box-shadow: var(--shadow-card);
  transition: transform 0.35s var(--ease), border-color 0.35s var(--ease),
              background 0.35s var(--ease), box-shadow 0.35s var(--ease);
  position: relative; overflow: hidden;
}
.svc__card::before { /* ghosted big index — a faint LIGHT ghost on a dark card */
  content: attr(data-n); position: absolute; right: 0.4rem; bottom: -1.2rem;
  /* 0.02, back down from the light build's 0.025: ink-on-white at equal alpha
     reads slightly heavier than white-on-ink, so the two are not the same number */
  font-family: var(--serif); font-size: 8rem; line-height: 1; color: rgba(234, 242, 255, 0.02);
  pointer-events: none;
}
.svc__card::after { /* top accent sweep on hover */
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: 0; transition: opacity 0.35s var(--ease);
}
/* white is the ceiling, so the hover lift is carried by the SHADOW rather than by
   a step up in surface value the way it was on black */
.svc__card:hover {
  transform: translateY(-4px); border-color: var(--hair-accent);
  background: var(--surface-2); box-shadow: var(--shadow-lift);
}
.svc__card:hover::after { opacity: 1; }
.svc__num {
  font-family: var(--serif); font-size: 0.95rem; color: var(--accent-label);
  text-shadow: var(--glow-accent);
  font-variant-numeric: tabular-nums; letter-spacing: 0.05em;
  display: inline-block; margin-bottom: 1.1rem;
}
.svc__card h3 { margin-bottom: 0.7rem; position: relative; }
.svc__card p { font-size: var(--fs-body); color: var(--muted); position: relative; }
.svc__go {
  margin-top: 1.2rem; display: inline-flex; align-items: center; color: var(--accent);
  opacity: 0; transform: translateX(-6px); transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}
.svc__go svg { width: 20px; height: 20px; }
.svc__card:hover .svc__go { opacity: 1; transform: none; }

/* ---- Approach — connected node path ----
   This section was already the mark's idea in list form: separate points held on
   one line. Under Constellation it stops being an analogy — the markers are the
   mark's own nodes, and .path::before is the axis they sit on. */
.approach { position: relative; }
.path { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; position: relative; }
.path::before {
  content: ""; position: absolute; top: 9px; left: 6%; right: 6%; height: 1px;
  background: linear-gradient(90deg, var(--hair-accent), var(--accent), var(--hair-accent)); opacity: 0.6;
}
.step { position: relative; padding-top: 2.6rem; }
/* 12px, not the 14px the diamond used: a rotated square is measured corner to
   corner, so matching the NUMBER would give a circle with visibly more ink than
   the marker it replaces. This matches the optical size instead. */
.step__node {
  position: absolute; top: 4px; left: 0; width: 12px; height: 12px;
  background: var(--accent); border-radius: 50%;
  box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.10), 0 2px 8px rgba(var(--accent-rgb), 0.30);
}
.step__num { font-size: var(--fs-micro); letter-spacing: 0.2em; color: var(--accent-label);
  text-transform: uppercase; font-weight: 600; margin-bottom: 0.5rem; display: block;
  text-shadow: var(--glow-accent); }
.step h3 { margin-bottom: 0.55rem; }
.step p { font-size: var(--fs-body); color: var(--muted); }

/* ---- Contact ---- */
.contact { text-align: center; }
.contact__inner {
  max-width: 760px; margin-inline: auto;
  background: var(--surface); border: 1px solid var(--hair-accent);
  border-radius: 20px; padding: clamp(2.6rem, 6vw, 4.5rem);
  position: relative; overflow: hidden;
  box-shadow: var(--shadow-card);
}
.contact__inner::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60% 60% at 50% 0%, rgba(var(--accent-rgb), 0.07), transparent 70%);
}
.contact__inner > * { position: relative; }
.contact__eyebrow { justify-content: center; }
.contact h2 { margin: 1rem 0; }
.contact .lead { max-width: 46ch; margin: 0 auto 2rem; }
.contact__cta { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: center; }
.contact__meta { margin-top: 2.2rem; color: var(--muted); font-size: 0.9rem;
  display: flex; gap: 1.5rem; justify-content: center; flex-wrap: wrap; }
.contact__meta a { color: var(--body); border-bottom: 1px solid var(--hair-accent); }
.contact__meta a:hover { color: var(--accent-strong); }

/* ---- Footer ---- */
.footer { border-top: 1px solid var(--hair); padding-block: 3.5rem 2.5rem; }
.footer__grid { display: flex; justify-content: space-between; align-items: flex-start; gap: 2rem; flex-wrap: wrap; }
/* The footer wears the lockup one step larger than the nav — it is the sign-off,
   and it has the room the nav doesn't. */
.footer__logo { display: inline-flex; align-items: center; gap: 0.75rem; margin-bottom: 1rem; }
.footer__logo .lockup__mark { width: 42px; height: 42px; }
.footer__logo .lockup__name { font-size: 1.2rem; }
.footer__logo .lockup__tag { font-size: 0.56rem; }
.footer__tag { color: var(--muted); font-size: 0.92rem; max-width: 30ch; }
.footer__keys { display: flex; gap: 0.75rem; flex-wrap: wrap; color: var(--body);
  font-size: 0.82rem; letter-spacing: 0.08em; text-transform: uppercase; margin-top: 1.2rem; }
.footer__keys span { color: var(--accent-label); }
.footer__col h4 { font-family: var(--sans); font-size: var(--fs-micro); letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted); font-weight: 600; margin-bottom: 0.9rem; }
.footer__col a { display: block; color: var(--body); font-size: 0.92rem; margin-bottom: 0.4rem; }
.footer__col a:hover { color: var(--accent-strong); }
.footer__bottom { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--hair);
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; color: var(--muted); font-size: 0.82rem; }

/* ---- Scroll reveal ---- (initial hidden state applies ONLY when JS is active) */
.reveal { transition: opacity 0.8s var(--ease), transform 0.8s var(--ease), filter 0.8s var(--ease); }
.js .reveal { opacity: 0; transform: translateY(24px); filter: blur(4px); }
.reveal.is-in { opacity: 1; transform: none; filter: none; }
.reveal[data-delay="1"] { transition-delay: 0.08s; }
.reveal[data-delay="2"] { transition-delay: 0.16s; }
.reveal[data-delay="3"] { transition-delay: 0.24s; }

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; filter: none; transition: none; }
  .js .reveal-line { opacity: 1; transform: none; filter: none; animation: none !important; }
  .hero__scroll span { display: none; }
  /* the mark holds its finished pose: frames unbreathed, nodes fully visible.
     The travelling stars simply stop where they are — being circles, there is no
     mid-roll pose for them to be caught in. */
  .facets svg, .ring, .fx-node, .fx-star, .fx-core,
  .facets::before, .orbiter { animation: none !important; }
  /* frozen at the TOP of each point's own swing, not all at 1 — flattening the
     supporting points to full strength would hand a reduced-motion viewer a
     busier mark than everyone else sees. */
  .fx-node { opacity: 1; }
  .fx-star { opacity: 0.62; }
}

/* ---- Responsive ---- */
@media (max-width: 1040px) {
  .facets { right: -20vw; opacity: 0.55; }
}
@media (max-width: 940px) {
  .about__grid { grid-template-columns: 1fr; }
  .svc { grid-template-columns: repeat(2, 1fr); }
  .values { grid-template-columns: repeat(2, 1fr); }
  .path { grid-template-columns: 1fr 1fr; }
  .path::before { display: none; }
  .hero__scroll { display: none; }
  /* keep the diamonds on small screens — they're the motif now — but drop them
     behind the type and well down in contrast so the headline still wins */
  .facets {
    right: -26vw; top: 40%; z-index: 1; opacity: 0.42;
    width: clamp(420px, 95vw, 620px);
  }
}
@media (max-width: 620px) {
  .vm { grid-template-columns: 1fr; }
  .svc { grid-template-columns: 1fr; }
  .values { grid-template-columns: 1fr; }
  .path { grid-template-columns: 1fr; }
  .footer__grid { flex-direction: column; }
  .hero__proof { display: none; }
  .facets { opacity: 0.34; }
  /* Nav only: the tagline goes, leaving mark + wordmark. Pinning it to one line
     (above) makes the lockup wider than the PNG it replaces, and the nav has a
     full-size CTA next to it — this drops the lockup to ~106px, NARROWER than
     V0.4.1's image, so the button gets more room here than it used to have.
     The footer keeps its tagline: single column, no competition for width. */
  .nav__logo .lockup__tag { display: none; }
}

/* =========================================================================
   PREVIEW HARNESS — not part of the Sidus design system.
   Two things that belong to the preview rather than to the brand:
     1. .vswitch — fixed version switcher, so a reviewer can reach the chooser
        or a sibling version from anywhere without using the Back button.
     2. .powered — the maker's credit in the footer.
   Both stay quiet on purpose: this must read as Naledi's site with NexusIQ as
   the enabler behind it, never as a co-brand.
   Delete this block (and its markup) when a version is promoted to production.
   ========================================================================= */

/* ---- Version switcher ---- */
.vswitch {
  position: fixed; z-index: 80;
  left: 50%; bottom: 1rem; transform: translateX(-50%);
  display: flex; align-items: center; gap: 0.2rem;
  padding: 0.32rem 0.38rem;
  border-radius: 999px;
  background: rgba(20, 29, 51, 0.88);   /* --surface, translucent */
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  backdrop-filter: saturate(140%) blur(14px);
  border: 1px solid var(--hair-2);
  box-shadow: 0 10px 30px -12px rgba(11, 17, 32, 0.30);
  font-family: var(--sans); font-size: 0.73rem; line-height: 1;
}
.vswitch__all {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.42rem 0.72rem; border-radius: 999px;
  color: var(--body); letter-spacing: 0.02em; white-space: nowrap;
  transition: color 0.25s var(--ease), background 0.25s var(--ease);
}
.vswitch__all::before {
  content: ""; width: 6px; height: 6px; background: var(--accent);
  border-radius: 50%; flex: none;
}
.vswitch__all:hover { color: var(--text); background: rgba(234, 242, 255, 0.08); }
.vswitch__rule { width: 1px; height: 15px; background: var(--hair-2); margin-inline: 0.18rem; flex: none; }
.vswitch__v {
  padding: 0.42rem 0.6rem; border-radius: 999px;
  color: var(--muted); font-weight: 600; letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  transition: color 0.25s var(--ease), background 0.25s var(--ease);
}
.vswitch__v:hover { color: var(--text); background: rgba(234, 242, 255, 0.08); }
.vswitch__v.is-current {
  /* label inverts with the pill: the accent is LIGHT here, so the type on it is
     the ground, not near-white as on the light build */
  color: #0B1120; background: linear-gradient(180deg, var(--accent-strong), var(--accent));
}
.vswitch__v.is-soon { opacity: 0.38; cursor: default; }
.vswitch__v.is-soon:hover { background: none; color: var(--muted); }

/* ---- Maker's credit ----
   The NexusIQ lockup is used exactly as supplied: its own brand guide forbids
   recolouring or restyling it. Because THIS version is a DARK ground, the correct
   supplied asset is the white-background lockup (nexusiq-apex-white.png, rendered
   from the guide's logos/nexusiq-logo-full-white.svg) — not the ink one V0.5 uses,
   which would be invisible here. Same rule, opposite asset:
   it fits by being SMALL and well spaced, never by being recoloured to her palette.
   Height 30px keeps it above the guide's 120px minimum lockup width. */
.powered {
  margin-top: 2.4rem; padding-top: 1.8rem;
  border-top: 1px solid var(--hair);
  display: flex; flex-direction: column; align-items: center; gap: 0.9rem;
  text-align: center;
}
.powered__label {
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--muted); opacity: 0.75;
}
.powered__logo { display: inline-block; }
.powered__logo img { height: 30px; width: auto; }
.powered__legal {
  font-size: 0.7rem; color: var(--muted); opacity: 0.6; letter-spacing: 0.01em;
  max-width: 68ch; line-height: 1.5;
}

/* The switcher is position:fixed, so it floats over whatever is at the bottom of
   the page — without this it sits on top of the last line of her footer (the
   company registration number). Reserve its height plus breathing room. */
.footer { padding-bottom: 5.5rem; }

/* Same problem at the top of the page: the hero's decorative proof strip lives
   bottom-centre too, and the pill lands squarely on "Botswana & beyond". Lift
   the strip clear while the harness is present — it goes back when this block
   is deleted. Must clear the strip's wrapped two-line height at ~700px wide. */
.hero__proof { bottom: 5.2rem; }

@media (max-width: 620px) {
  /* The pill row grows every time a version is added. At seven pills it already
     overran a 390px viewport — SILENTLY, because body{overflow-x:hidden} clips it
     instead of scrolling, so the outermost version just vanished off the edge.
     Two fixes, belt and braces: tighten the pills so the common 390px case still
     fits outright, and cap the bar to the viewport with a scroll so no version is
     ever unreachable however many get added later.
     flex:none is load-bearing — flex items shrink by default, so without it the
     pills squash to fit instead of scrolling. */
  .vswitch {
    font-size: 0.68rem; gap: 0.1rem;
    max-width: calc(100vw - 1.5rem);
    overflow-x: auto;
    scrollbar-width: none;
    justify-content: flex-start;
  }
  .vswitch::-webkit-scrollbar { display: none; }
  .vswitch__all span { display: none; }
  /* Pin the way back. Once the bar scrolls the current pill into view (see the
     script beside the .vswitch markup), "All versions" would otherwise be carried
     off the left edge — trading one unreachable control for another. Sticky keeps
     it parked while the pills slide underneath, so both the escape hatch and your
     current position are visible at once.

     Two pieces of paint, and neither is decoration:

       · The -8px shadow slab covers the bar's own horizontal padding. That strip
         is part of the scrollable area, so without it a pill stays visible in the
         ~6px to the LEFT of the pinned one. A negative margin-left does NOT fix
         this — once the element is stuck its border box is clamped to the
         scrollport edge and the margin is ignored, so it has to be painted over.
       · ::after is a short dissolve on the RIGHT. A hard edge there (a 1px rule,
         or just the pill's own boundary) slices whichever pill happens to be
         passing under it clean through the middle of a glyph — "V0.4" renders as
         "0.4" and reads as a rendering fault. Fading it out over 16px is what
         makes the pill look pinned rather than broken.

     Both use an OPAQUE colour, not the bar's translucent fill — pills visible
     THROUGH the pinned pill is the same fault by another route. It is the bar's
     own colour with the alpha removed, so the seam doesn't show. */
  .vswitch__all {
    position: sticky; left: 0; z-index: 1;
    padding-inline: 0.6rem 0.5rem;
    background: #141D33;
    box-shadow: -8px 0 0 #141D33;
    flex: none;   /* flex items shrink by default; without this the pill squashes
                     instead of the bar scrolling */
  }
  .vswitch__all::after {
    content: ""; position: absolute; left: 100%; top: 0; bottom: 0; width: 16px;
    background: linear-gradient(90deg, #141D33, rgba(0, 0, 0, 0));
    pointer-events: none;
  }
  /* diamond only, keep the pill narrow */
  .vswitch__v { padding-inline: 0.42rem; flex: none; }
  .vswitch__rule { margin-inline: 0.1rem; }
}
