/* NEUON AI — Dr. KC visual direction. Brand rules: only these three
   colours (Brand Book) — blue/black/white — self-hosted Inter. */
@font-face { font-family:'Inter'; font-weight:400; font-display:swap; src:url('/assets/fonts/inter-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family:'Inter'; font-weight:700; font-display:swap; src:url('/assets/fonts/inter-latin-700-normal.woff2') format('woff2'); }

:root {
  --blue:#0078FF; --black:#0A0203; --white:#FFFFFF;
  --blue-deep:#004fa8; --blue-pale:#eaf3ff;
}
html { overflow-x:clip; }
* { margin:0; padding:0; box-sizing:border-box; }
html { scroll-behavior:smooth; }
body {
  font-family:'Inter',Helvetica,Arial,sans-serif; color:var(--black); background:var(--white);
  line-height:1.5; overflow-x:hidden;
  /* clip on the ELEMENT that scrolls, too. overflow-x:hidden on body alone
     still lets iOS pan the page when something inside is too wide, and a
     panned page looks like the left edge has been cut off. */
  overflow-x:clip;
}
h1,h2,h3,h4 { font-weight:700; line-height:1.15; }
button { font-family:inherit; }

/* ---- slideshow deck: each section fills the viewport, scroll snaps ----
   min-height (not fixed height) so a tall slide grows instead of pushing
   its own content up behind the fixed nav bar.

   ONE SCROLLBAR, and it is the page's.
   The deck used to be `height:100vh; overflow-y:auto` — a scroller of its own —
   while the Starter Pack, the arcade and the footer sat underneath it in the
   page's scrollbar. So a wheel that reached the bottom of NEUFAMILY simply
   stopped: the deck had run out, and the rest of the site was behind a second
   scrollbar you had to go and find with the mouse. Now the document scrolls
   everything and the snapping moves up to the root with it, which is also what
   lets a phone's address bar collapse the way it does on every other page. */
.deck-page { scroll-snap-type:y mandatory; }
.slide {
  scroll-snap-align:start; scroll-snap-stop:always;
  min-height:100vh; width:100%; position:relative; overflow:hidden;
  display:flex; flex-direction:column; justify-content:center;
  /* Clearance is measured from the DISC, not the bar. The disc hangs below the
     bar and is now half as big again as it was, so a section measured against
     var(--nav-h) had its heading running underneath it — which is exactly what
     happened to OUR COMMITMENT. */
  padding:calc(var(--nav-disc) + 1.6rem) clamp(1.6rem,6vw,6rem) 3rem;
}
/* What comes after the deck has to be snap stops too. Mandatory snapping will
   not come to rest anywhere that isn't one, so without these the page slides
   back up to NEUFAMILY the moment you let go of the wheel — the same dead end
   in a new disguise. The footer aligns to `end`, its bottom against the
   viewport's, because that is where the page stops scrolling anyway. */
.deck-page .pack, .deck-page .arcade { scroll-snap-align:start; }
.deck-page .pgfoot { scroll-snap-align:end; }

.slide--light { background:var(--white); color:var(--black); }
.slide--dark { background:var(--black); color:var(--white); }
.slide--blue { background:var(--blue); color:var(--white); }
.slide__title { font-size:clamp(2rem,4.4vw,3.4rem); letter-spacing:-0.01em; margin-bottom:1rem; }
.slide__title--hero { color:var(--white); font-size:clamp(2.1rem,5vw,3.8rem); max-width:44rem; position:relative; z-index:2; }
.kicker { font-weight:700; letter-spacing:0.14em; text-transform:uppercase; font-size:0.85rem; color:var(--blue); margin-bottom:0.6rem; }
.slide--dark .kicker, .slide--blue .kicker { color:var(--white); opacity:0.85; }
.lede { font-size:clamp(1.05rem,1.6vw,1.3rem); max-width:40rem; opacity:0.85; margin-bottom:1.4rem; }
.lede--light { color:var(--white); opacity:0.92; }
.btn { border-radius:999px; padding:0.85rem 1.7rem; font-weight:700; font-size:0.95rem; cursor:pointer; border:2px solid var(--white); transition:transform 0.2s ease; }
.btn:hover { transform:translateY(-2px); }
.btn--white { background:var(--white); color:var(--blue); }
.btn--outline { background:transparent; color:var(--white); }

/* ---- nav: fixed floating capsule/pill ---- */
/* the bar is shorter than the circle that sits on it — see .nav__brand */
/* Dr. KC, on seeing it on the big screen: "Make this logo. Make it bigger."
   The disc is the one thing a room full of people looks at first, and at the
   old size the mark inside it was a smudge from four metres away. Everything
   in the credentials dome is sized off this number, so growing it grows the
   certificates with it. */
:root { --nav-h:3.9rem; --nav-disc:clamp(6.6rem,10.5vw,9.5rem); }
/* The capsule is centred on its own. The search button is taken out of the
   flow and hung off the pill's right edge, so adding it can never pull the
   logo off centre — the disc has to sit dead centre for the credentials
   circle to open symmetrically behind it. */
/* Dr. KC's bar: a full-width white bar with smooth bottom corners, not a
   floating capsule. The blue NEUON circle sits on it, centred, hanging below
   its lower edge, with radar waves rolling out of it. */
.nav { position:fixed; top:0; left:0; right:0; z-index:80; display:block; pointer-events:none; }
.nav__search {
  position:absolute; right:clamp(1.2rem,4vw,3rem); top:50%; transform:translateY(-50%);
  pointer-events:auto; width:2.8rem; height:2.8rem; border-radius:50%;
  background:var(--blue-pale); border:0; color:var(--blue); cursor:pointer;
  display:grid; place-items:center; padding:0;
  transition:background 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.nav__search:hover { background:var(--blue); color:var(--white); transform:translateY(-50%) scale(1.06); }

/* NEU's face, immediately left of the search button and the same size — the
   two sit together because they answer the same instinct: "I want to ask this
   website something". Positioned off the same right-hand edge, one button's
   width further in, so neither can pull the logo off centre. */
.nav__neu {
  position:absolute; right:calc(clamp(1.2rem,4vw,3rem) + 3.3rem); top:50%; transform:translateY(-50%);
  pointer-events:auto; width:2.8rem; height:2.8rem; border-radius:50%;
  background:var(--blue-pale); border:0; cursor:pointer; padding:0;
  display:grid; place-items:center; overflow:visible;
  transition:background 0.2s ease, transform 0.2s ease;
}
.nav__neu img {
  width:2.5rem; height:2.5rem; object-fit:contain; object-position:top center;
  border-radius:50%; display:block;
}
.nav__neu:hover { background:var(--blue); transform:translateY(-50%) scale(1.06); }
/* the little padlock, while it is still asleep */
.nav__neulock {
  position:absolute; right:-0.1rem; bottom:-0.1rem;
  width:1.05rem; height:1.05rem; border-radius:50%;
  background:var(--white); color:var(--blue);
  display:grid; place-items:center;
  box-shadow:0 1px 4px rgba(10,2,3,0.28);
}
/* a gentle look-at-me, once, so it is noticed without nagging */
.nav__neu.is-new { animation:navneu-hi 2.4s ease 1.2s 2; }
@keyframes navneu-hi {
  0%, 100% { transform:translateY(-50%) rotate(0); }
  8%  { transform:translateY(-50%) rotate(-9deg); }
  16% { transform:translateY(-50%) rotate(7deg); }
  24% { transform:translateY(-50%) rotate(0); }
}
@media (prefers-reduced-motion: reduce) { .nav__neu.is-new { animation:none; } }

/* On the main page the face in the bar IS the way in, so the floating bubble
   would be the same door twice. The panel it opens is the same one. */
body:has(.nav__neu) .nchat__bubble { display:none; }

/* No phone override. The first version shrank the face to 2.5rem while the
   search button stayed 2.8rem, which left them different sizes three pixels
   apart — a pair that reads as two of the same thing has to BE two of the same
   thing. There is room for both at full size even at 375px: the logo disc
   drops to its own minimum on a narrow screen and never reaches them. */
.nav__pill {
  position:relative;   /* anchors the search button to the bar's edge */
  pointer-events:auto; display:flex; align-items:center; justify-content:center;
  gap:clamp(1rem,2.6vw,2.4rem);
  background:var(--white); padding:0.85rem clamp(1.2rem,4vw,3rem);
  height:var(--nav-h);
  border-radius:0 0 clamp(1rem,2vw,1.8rem) clamp(1rem,2vw,1.8rem);
  box-shadow:0 10px 30px rgba(10,2,3,0.13);
  overflow:visible;    /* the circle hangs past the bottom edge */
}
/* equal-width sides keep the disc on the capsule's true centre */
.nav__side { display:flex; align-items:center; gap:clamp(1rem,2.6vw,2.4rem); flex:1 1 0; min-width:0; }
.nav__side--l { justify-content:flex-end; }
.nav__side--r { justify-content:flex-start; }
.nav__pill a:not(.nav__brand) { color:var(--blue); text-decoration:none; font-weight:700; font-size:0.95rem; opacity:0.6; transition:opacity 0.2s ease; white-space:nowrap; }
.nav__pill a:not(.nav__brand):hover, .nav__pill a.active { opacity:1; }
/* The circle is bigger than the bar and hangs below it. The button keeps a
   fixed width in the flow so it still reserves the centre slot, while the
   image itself is taken out of flow so it can overflow downward without
   stretching the bar. */
.nav__brand { width:var(--nav-disc); align-self:stretch; flex:none; }
/* solid blue circle carrying the white mark — Dr. KC's slide */
.nav__disc {
  position:absolute; left:50%; top:0.2rem; transform:translateX(-50%);
  width:var(--nav-disc); height:var(--nav-disc); border-radius:50%;
  background:var(--blue); display:grid; place-items:center; z-index:2;
  box-shadow:0 8px 22px -6px color-mix(in srgb, var(--blue) 65%, transparent);
  transition:transform 0.25s ease, box-shadow 0.25s ease;
}
.nav__disc img { width:70%; height:auto; display:block; }
.nav__brand--btn:hover .nav__disc {
  transform:translateX(-50%) scale(1.06);
  box-shadow:0 10px 30px -6px color-mix(in srgb, var(--blue) 85%, transparent);
}
.nav__brand--btn:active .nav__disc { transform:translateX(-50%) scale(0.97); }

/* radar waves rolling out of the circle, always running — the same language
   as the rings on "We Teach, It Learn", so it reads as a live control */
.nav__radar {
  position:absolute; left:50%; top:calc(0.2rem + var(--nav-disc) / 2);
  transform:translate(-50%,-50%); pointer-events:none; z-index:1;
}
.nav__radar i {
  position:absolute; left:50%; top:50%;
  width:var(--nav-disc); height:var(--nav-disc);
  margin-left:calc(var(--nav-disc) / -2);
  margin-top:calc(var(--nav-disc) / -2);
  border:2px solid var(--blue); border-radius:50%; opacity:0;
  animation:nav-radar 3s ease-out infinite;
}
.nav__radar i:nth-child(2) { animation-delay:1s; }
.nav__radar i:nth-child(3) { animation-delay:2s; }
@keyframes nav-radar {
  0%   { transform:scale(0.96); opacity:0.55; }
  100% { transform:scale(1.9);  opacity:0; }
}
@media (prefers-reduced-motion:reduce) { .nav__radar i { animation:none; } }

/* ---- mobile burger (hidden on desktop) ---- */
.nav__burger {
  display:none; background:none; border:0; cursor:pointer; padding:0.4rem;
  flex-direction:column; gap:5px; width:2.2rem;
}
.nav__burger span { display:block; height:2px; width:20px; background:var(--blue); border-radius:2px; transition:transform 0.25s ease, opacity 0.2s ease; }
.nav__burger.is-open span:nth-child(1) { transform:translateY(7px) rotate(45deg); }
.nav__burger.is-open span:nth-child(2) { opacity:0; }
.nav__burger.is-open span:nth-child(3) { transform:translateY(-7px) rotate(-45deg); }

/* ---- mobile drawer ---- */
.drawer {
  position:fixed; inset:0; z-index:75; background:var(--white);
  padding:calc(var(--nav-h) + 1.6rem) 1.6rem 2rem; overflow-y:auto;
  animation:drawer-in 0.25s ease;
}
@keyframes drawer-in { from { opacity:0; transform:translateY(-8px); } }
.drawer__label { font-size:0.72rem; font-weight:700; letter-spacing:0.14em; text-transform:uppercase; color:var(--blue); margin:1.2rem 0 0.6rem; }
.drawer__links { display:grid; gap:0.1rem; }
.drawer__links a {
  display:block; padding:0.85rem 0.4rem; color:var(--black); text-decoration:none;
  font-weight:700; font-size:1.05rem; border-bottom:1px solid var(--line, #e8e8ea);
}
.drawer__links a:active { background:var(--blue-pale); }
.drawer__links--chapters a { font-size:0.98rem; color:var(--blue-deep); }
body.drawer-open, body.search-open { overflow:hidden; }

/* ---- search overlay ---- */
.search {
  position:fixed; inset:0; z-index:90; background:rgba(10,2,3,0.55);
  backdrop-filter:blur(4px); display:flex; justify-content:center;
  padding:calc(var(--nav-h) + 1.2rem) 1.2rem 2rem;
}
/* an explicit display value beats the `hidden` attribute, so restore it */
.search[hidden], .drawer[hidden] { display:none; }
.search__box { width:min(38rem,100%); background:var(--white); border-radius:18px; overflow:hidden; box-shadow:0 30px 70px rgba(0,0,0,0.4); max-height:100%; display:flex; flex-direction:column; }
.search__field { display:flex; align-items:center; gap:0.7rem; padding:1rem 1.2rem; border-bottom:1px solid #ececee; color:var(--blue); }
.search__field input { flex:1; border:0; outline:none; font:400 1.05rem 'Inter',sans-serif; color:var(--black); background:none; }
.search__close { background:none; border:0; cursor:pointer; font-size:1rem; color:var(--black); opacity:0.5; }
.search__close:hover { opacity:1; }
.search__results { list-style:none; overflow-y:auto; }
.search__results a { display:flex; align-items:baseline; gap:0.7rem; padding:0.85rem 1.2rem; text-decoration:none; color:var(--black); font-size:0.95rem; border-bottom:1px solid #f4f4f6; }
.search__results a:hover { background:var(--blue-pale); }
.search__kind { flex:none; font-size:0.66rem; font-weight:700; letter-spacing:0.1em; text-transform:uppercase; color:var(--blue); border:1px solid currentColor; border-radius:999px; padding:0.1rem 0.45rem; }
.search__empty { padding:1.2rem; opacity:0.6; font-size:0.92rem; }

/* ---- side rail: dots marking each slide, click to jump ---- */
.rail { position:fixed; right:1.4rem; top:50%; transform:translateY(-50%); z-index:70; display:flex; flex-direction:column; gap:0.6rem; }
/* P&G-style rail: quiet blue dots that glow, with the active one lit and
   labelled on hover so a presenter can see where they are in the running order */
.rail { align-items:flex-end; }
.rail__dot {
  position:relative; width:9px; height:9px; border-radius:50%;
  background:color-mix(in srgb, var(--blue) 32%, transparent);
  border:0; cursor:pointer; padding:0;
  transition:background 0.25s ease, transform 0.25s ease, box-shadow 0.3s ease;
}
.rail__dot:hover { background:var(--blue); transform:scale(1.3); }
.rail__dot.active {
  background:var(--blue); transform:scale(1.5);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--blue) 22%, transparent),
             0 0 12px 2px color-mix(in srgb, var(--blue) 70%, transparent);
  animation:rail-glow 2.4s ease-in-out infinite;
}
@keyframes rail-glow {
  0%,100% { box-shadow:0 0 0 3px color-mix(in srgb, var(--blue) 20%, transparent),
                       0 0 10px 1px color-mix(in srgb, var(--blue) 55%, transparent); }
  50%     { box-shadow:0 0 0 6px color-mix(in srgb, var(--blue) 10%, transparent),
                       0 0 18px 4px color-mix(in srgb, var(--blue) 85%, transparent); }
}
/* the pill label, as on us.pg.com */
.rail__dot::after {
  content:attr(data-label); position:absolute; right:calc(100% + 0.7rem); top:50%;
  transform:translateY(-50%) translateX(6px); white-space:nowrap;
  background:var(--white); color:var(--blue); font-weight:700; font-size:0.78rem;
  padding:0.35rem 0.85rem; border-radius:999px;
  box-shadow:0 8px 22px -8px rgba(10,2,3,0.3);
  opacity:0; pointer-events:none; transition:opacity 0.2s ease, transform 0.2s ease;
}
.rail__dot:hover::after, .rail__dot.active::after { opacity:1; transform:translateY(-50%) translateX(0); }
@media (prefers-reduced-motion:reduce) { .rail__dot.active { animation:none; } }

/* ---- hero + certified badges (shared abstract "aerial terrain" backdrop) ---- */
/* A still, not a film. The looping video made the section stutter on the
   laptops this is presented from — section 1 already animates a reel of cards
   over the top of it, and asking the same machine to decode video underneath
   that was one job too many. The picture is a frame of the same footage, so
   nothing was lost but the movement.

   The plate is bright silver and the headline over it is white, so it is
   dimmed and cooled toward the brand blue here rather than in the file — that
   way the same photograph can be reused somewhere brighter. */
.hero__bg {
  position:absolute; inset:0; z-index:0;
  background:url('/assets/video/hero-kid-globe.jpg') center center/cover no-repeat, #08131f;
  filter:brightness(0.62) contrast(1.06) saturate(1.15) hue-rotate(-6deg);
}
/* a phone does not need the 1920px plate */
@media (max-width:820px) {
  .hero__bg { background-image:url('/assets/video/hero-kid-globe-sm.jpg'); }
}

/* Two washes, not one: a dark band top and bottom so the kicker, the headline
   and the film reel all keep their contrast, and a blue cast through the
   middle so the plate belongs to the rest of the site. */
.hero__scrim {
  position:absolute; inset:0; z-index:1;
  background:
    linear-gradient(180deg,
      rgba(4,10,20,0.78) 0%,
      rgba(4,10,20,0.30) 26%,
      rgba(4,10,20,0.34) 62%,
      rgba(4,10,20,0.86) 100%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--blue) 26%, transparent),
      color-mix(in srgb, var(--blue) 10%, transparent));
}
.slide--hero { align-items:flex-start; }
.slide--certified { align-items:center; }

/* ---- certified badge disc ---- */
.badge-disc {
  position:relative; z-index:2; background:var(--white); border-radius:50%;
  width:min(30rem,86vw); aspect-ratio:1; display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:1rem; padding:3rem 2rem; box-shadow:0 30px 70px rgba(0,0,0,0.35);
}
.badge-disc__logo { height:64px; }
.badge-disc__list { list-style:none; display:flex; flex-wrap:wrap; gap:0.6rem 1rem; justify-content:center; max-width:22rem; }
/* ---- logo placeholders: plain blue shape + "L", real logos come later ---- */
.logo-ph {
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--blue); color:var(--white); font-weight:700;
  border-radius:8px; flex:none; line-height:1;
}
.badge-disc__list li { width:2.6rem; height:2.6rem; font-size:1.1rem; }

/* ---- We Teach, It Learn ---- */
.teach { position:relative; display:flex; flex-direction:column; align-items:center; text-align:center; gap:2.2rem; }
.teach__brain { width:min(20rem,60vw); aspect-ratio:1; display:flex; align-items:center; justify-content:center; }
.brain-ring { fill:none; stroke:var(--blue); stroke-width:1.4; opacity:0.5; }
.brain-ring--in { stroke-width:2.4; opacity:0.9; }
.teach__domains { list-style:none; display:flex; gap:1rem; flex-wrap:wrap; justify-content:center; }
.teach__domains li { border:1px solid color-mix(in srgb, var(--white) 30%, transparent); padding:0.5rem 1.1rem; border-radius:999px; font-size:0.85rem; font-weight:700; }

/* ---- Sovereign Applied AI (map hub + orbit; see orbit section below) ---- */
.slide#sovereign { align-items:center; text-align:center; }
.compact-quote { border-left:4px solid var(--blue); border-radius:14px; background:var(--blue-pale); padding:1.4rem 1.8rem; max-width:34rem; margin:0 auto; text-align:left; }
.compact-quote h4 { color:var(--blue); font-size:0.85rem; letter-spacing:0.08em; text-transform:uppercase; margin-bottom:0.4rem; }

.slide--blue.slide#how-it-works { align-items:center; text-align:center; }

/* ---- Our Commitment ---- */
.commit__row { display:flex; align-items:center; justify-content:space-between; gap:2rem; flex-wrap:wrap; }
.thanks { font-weight:700; color:var(--blue); margin-top:1rem; }
.seal { flex:none; width:8rem; height:8rem; border-radius:50%; border:3px dashed var(--blue); display:flex; align-items:center; justify-content:center; text-align:center; font-weight:700; color:var(--blue); font-size:0.8rem; }
.logo-strip { list-style:none; display:flex; flex-wrap:wrap; gap:1rem; margin-top:2.6rem; }
.logo-strip li { width:4.4rem; height:2.8rem; font-size:1.2rem; border-radius:8px; }

/* ---- SDG ---- */
.sdg__title { color:var(--blue); }
.sdg__band { display:grid; grid-template-columns:repeat(3,1fr); gap:0.6rem; margin-top:1.6rem; max-width:60rem; }
.sdg__photo { aspect-ratio:4/3; border-radius:10px; }
.sdg__photo--sea { background:linear-gradient(160deg,#bcdcee,#5c8fae); }
.sdg__photo--earth { background:radial-gradient(circle at 40% 40%, #2f6fae, #06162b); }
.sdg__photo--forest { background:linear-gradient(160deg,#c9e6a8,#3f7a3f); }

/* ---- NEUGrowth / IPO 2030 ---- */
.slide#growth { align-items:center; text-align:center; }
.phase-row { list-style:none; display:grid; grid-template-columns:repeat(4,minmax(160px,1fr)); gap:1.2rem; margin-top:1.6rem; max-width:64rem; }
.phase-row li { border:1px solid color-mix(in srgb, var(--white) 25%, transparent); border-top:3px solid var(--blue); border-radius:12px; padding:1.2rem 1rem; text-align:left; }
.phase-row__period { color:var(--blue); font-weight:700; font-size:0.8rem; }
.phase-row h3 { font-size:1rem; margin:0.3rem 0; }
.phase-row p { font-size:0.8rem; opacity:0.75; }

/* ---- News grid ---- */
.news-grid { list-style:none; display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:1.2rem; margin-top:1.6rem; max-width:64rem; }
.news-card { border:1px solid color-mix(in srgb, var(--black) 12%, var(--white)); border-radius:14px; padding:1.4rem; }
.news-card__tag { color:var(--blue); font-weight:700; font-size:0.75rem; letter-spacing:0.08em; text-transform:uppercase; }
.news-card p { margin-top:0.5rem; font-size:0.92rem; }

/* ---- NEUAllies ---- */
.slide#allies { align-items:flex-start; }
.allies__card { border:1px solid color-mix(in srgb, var(--white) 25%, transparent); border-radius:14px; padding:1.4rem 1.8rem; margin-top:1rem; }
.allies__card h4 { color:var(--blue); }

/* ---- NEUFamily ---- */
.family__row { display:flex; align-items:center; justify-content:space-between; gap:3rem; flex-wrap:wrap; }
.family__photo { width:min(22rem,70vw); aspect-ratio:1; border-radius:50%; background:radial-gradient(circle at 35% 30%, #cfe0f7, #6f8fbf); flex:none; }
.family__ctas { display:flex; gap:1rem; margin-top:1.2rem; flex-wrap:wrap; }
.grain__heading { margin-top:2.6rem; }
.grain-row { list-style:none; display:grid; grid-template-columns:repeat(5,1fr); gap:1rem; margin-top:1rem; }
.grain-row li { background:rgba(255,255,255,0.12); border-radius:12px; padding:1rem 0.9rem; font-size:0.82rem; }
.grain-row__letter { display:block; font-size:1.3rem; font-weight:700; margin-bottom:0.3rem; }
.grain-row strong { display:block; margin-bottom:0.3rem; }

/* ---- footer ---- */
.footer { background:var(--black); color:var(--white); text-align:center; padding:4rem 1.4rem; }
.footer__logo { height:70px; margin-bottom:1rem; }
.footer__signature { font-weight:700; font-size:1.2rem; }
.footer__heritage { opacity:0.75; margin-top:0.4rem; }
.footer__links { display:flex; gap:1.6rem; justify-content:center; margin:1.6rem 0; flex-wrap:wrap; }
.footer__links a { color:var(--white); opacity:0.8; text-decoration:none; font-size:0.88rem; }
.footer__links a:hover { opacity:1; }
/* News lives here rather than in the top bar — give it a pill so it still
   reads as a destination, not just another footer link */
.footer__news {
  border:1.5px solid rgba(255,255,255,0.35); border-radius:999px;
  padding:0.4rem 1.1rem; font-weight:700; opacity:1 !important;
  transition:background 0.2s ease, border-color 0.2s ease;
}
.footer__news:hover { background:var(--blue); border-color:var(--blue); }
.footer__constellation-label { font-size:0.75rem; letter-spacing:0.1em; text-transform:uppercase; color:var(--blue); margin-top:2rem; }
.footer__links--constellation { margin-top:0.8rem; }
.footer__base { opacity:0.5; font-size:0.8rem; }

/* ================= radar-glow hover (round elements) ================= */
.radar { position:relative; cursor:pointer; transition:transform 0.3s ease; }
.radar:hover, .radar:focus-visible { transform:scale(1.02); }
.radar::before, .radar::after {
  content:''; position:absolute; inset:0; border-radius:50%;
  border:2px solid var(--blue); opacity:0; pointer-events:none;
}
.radar:hover::before, .radar:focus-visible::before { animation:radar-ping 1.6s ease-out infinite; }
.radar:hover::after, .radar:focus-visible::after { animation:radar-ping 1.6s ease-out 0.8s infinite; }
@keyframes radar-ping {
  0%   { transform:scale(1); opacity:0.65; }
  100% { transform:scale(1.55); opacity:0; }
}

/* ================= orbit: nodes revolving around a hub ================= */
.orbit {
  position:relative; width:100%; max-width:80rem; margin:0 auto;
  height:clamp(26rem,58vh,38rem); outline:none;
  --orbit-rx:440; --orbit-ry:138; --orbit-min-scale:0.38;
  touch-action:pan-y;
}
.orbit__hub {
  position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  text-align:center; z-index:50; pointer-events:none; width:min(30rem,60vw);
}
.orbit__hub .slide__title { margin:0; }
.orbit__hint { font-size:0.78rem; opacity:0.7; margin-top:0.5rem; letter-spacing:0.04em; }
.orbit__ring { list-style:none; position:absolute; inset:0; }
.orbit__node {
  position:absolute; top:50%; left:50%; width:8rem;
  transition:opacity 0.2s linear; will-change:transform;
}
.orbit__node a, .orbit__node > .orbit__disc {
  display:flex; flex-direction:column; align-items:center; gap:0.7rem;
  text-decoration:none; color:inherit;
}
.orbit__node a { cursor:pointer; }
/* the round face — dark core with a lit rim, so it reads as a glowing
   orb against the blue slide instead of washing out into it */
.orbit__disc {
  width:8rem; height:8rem; border-radius:50%; position:relative;
  display:grid; place-items:center; flex:none;
  background:radial-gradient(circle at 36% 30%, #14385f 0%, #0a2036 52%, #050d16 100%);
  box-shadow:0 20px 44px -10px rgba(0,0,0,0.6), 0 0 0 2px rgba(255,255,255,0.9) inset,
             0 0 26px 2px rgba(255,255,255,0.28);
  transition:box-shadow 0.3s ease;
}
.orbit__disc-in {
  width:50%; height:50%; border-radius:50%;
  border:2px solid rgba(255,255,255,0.9);
  box-shadow:0 0 18px 2px rgba(0,120,255,0.9) inset, 0 0 12px rgba(255,255,255,0.5);
}
/* per-node accent variation, still blue/white/black only */
.orbit__disc--1 .orbit__disc-in { box-shadow:0 0 18px 3px rgba(0,120,255,1) inset, 0 0 14px rgba(255,255,255,0.6); }
.orbit__disc--2 { background:radial-gradient(circle at 62% 32%, #16406c 0%, #0a2036 54%, #050d16 100%); }
.orbit__disc--3 { background:radial-gradient(circle at 32% 64%, #0f2f52 0%, #081a2c 54%, #040a12 100%); }
.orbit__disc--4 { background:radial-gradient(circle at 50% 26%, #1a4778 0%, #0a2036 52%, #050d16 100%); }
.orbit__disc--5 { background:radial-gradient(circle at 40% 60%, #0d2a49 0%, #071626 54%, #040a12 100%); }
.orbit__disc--6 { background:radial-gradient(circle at 64% 58%, #16406c 0%, #0a2036 52%, #050d16 100%); }
.orbit__disc--7 { background:radial-gradient(circle at 28% 42%, #12365c 0%, #081a2c 54%, #040a12 100%); }
.orbit__label {
  font-weight:700; font-size:1.05rem; text-align:center; line-height:1.25;
  text-shadow:0 2px 10px rgba(0,0,0,0.45);
}
.orbit__label em { display:block; font-style:normal; font-weight:400; font-size:0.76rem; opacity:0.85; margin-top:0.25rem; }
/* front-most node gets the radar ping + full-strength face */
.orbit__node.is-front .orbit__disc { box-shadow:0 26px 60px -14px rgba(0,0,0,0.6), 0 0 0 3px rgba(255,255,255,0.7) inset, 0 0 34px 4px rgba(255,255,255,0.35); }
.orbit__node.is-front .orbit__disc::before,
.orbit__node.is-front .orbit__disc::after {
  content:''; position:absolute; inset:0; border-radius:50%;
  border:2px solid rgba(255,255,255,0.9); opacity:0; pointer-events:none;
  animation:radar-ping 2s ease-out infinite;
}
.orbit__node.is-front .orbit__disc::after { animation-delay:1s; }
.orbit__nav {
  position:absolute; top:50%; transform:translateY(-50%); z-index:60;
  width:3rem; height:3rem; border-radius:50%; border:0; cursor:pointer;
  background:var(--white); color:var(--blue); font-size:1.6rem; line-height:1;
  box-shadow:0 10px 26px rgba(0,0,0,0.3); transition:transform 0.2s ease;
}
.orbit__nav:hover { transform:translateY(-50%) scale(1.1); }
.orbit__nav--prev { left:0; }
.orbit__nav--next { right:0; }

/* ---- sovereign slide: map hub + 4 dimensions in orbit ---- */
.sov__head { text-align:center; max-width:44rem; margin:0 auto 0.6rem; }
.sov__head .lede { margin-left:auto; margin-right:auto; }
/* card rings need more room than disc rings — the cards are ~4x the area, so
   the ellipse widens and deepens and the back of the ring stays legible */
/* A card is ~240px tall, so the ring's vertical radius plus half a card must
   stay inside the container — otherwise the front card is clipped by the
   slide's overflow:hidden. Hence the flatter ellipse and the taller box. */
.orbit--sov { --orbit-rx:420; --orbit-ry:104; --orbit-min-scale:0.52; height:clamp(31rem,60vh,38rem); }
.orbit--how { --orbit-rx:470; --orbit-ry:118; --orbit-min-scale:0.44; height:clamp(33rem,66vh,42rem); }
.orbit--sov .orbit__hub, .orbit--how .orbit__hub { z-index:1; }  /* cards pass in front */
.orbit--sov .orbit__node--card { width:clamp(11rem,16vw,13.5rem); }
.orbit--sov .orbit__node { width:9rem; }
.orbit--sov .orbit__disc { width:6.2rem; height:6.2rem; }
/* only the front node shows its description, so labels never stack up */
.orbit--sov .orbit__label em { display:none; }
.orbit--sov .orbit__node.is-front .orbit__label em { display:block; }
.slide#sovereign .compact-quote { margin-top:1.6rem; }
.orbit__hub--map { width:min(46rem,86vw); }
.sarawak { width:100%; height:auto; display:block; overflow:visible; }
.sw-traces path {
  stroke-dasharray:26 200; stroke-dashoffset:0;
  animation:sw-flow 5.5s linear infinite;
}
.sw-traces path:nth-child(2) { animation-duration:6.8s; animation-delay:-1.2s; }
.sw-traces path:nth-child(3) { animation-duration:4.9s; animation-delay:-2.4s; }
.sw-traces path:nth-child(4) { animation-duration:7.6s; animation-delay:-0.6s; }
.sw-traces path:nth-child(5) { animation-duration:6.1s; animation-delay:-3.1s; }
@keyframes sw-flow { to { stroke-dashoffset:-1130; } }
.sw-pad { animation:sw-pad 2.6s ease-in-out infinite; animation-delay:var(--d,0s); transform-box:fill-box; transform-origin:center; }
@keyframes sw-pad {
  0%,100% { opacity:0.45; transform:scale(1); }
  50%     { opacity:1;    transform:scale(1.5); }
}
.sw-core { animation:sw-core 3.4s ease-in-out infinite; transform-box:fill-box; transform-origin:center; }
@keyframes sw-core { 0%,100% { opacity:0.9; } 50% { opacity:1; } }
.sw-label { fill:var(--white); font:700 13px/1 'Inter',sans-serif; letter-spacing:0.16em; opacity:0.9; }
.sw-place { fill:var(--blue); font:700 22px/1 'Inter',sans-serif; letter-spacing:0.3em; opacity:0.55; }
.compact-quote--dark { background:rgba(0,120,255,0.10); border-left-color:var(--blue); color:var(--white); }
.compact-quote--dark h4 { color:var(--blue); }
@media (prefers-reduced-motion:reduce) {
  .sw-traces path, .sw-pad, .sw-core { animation:none; }
  .orbit__node.is-front .orbit__disc::before, .orbit__node.is-front .orbit__disc::after { animation:none; }
}

/* ================= pillar detail pages (M3 subpages) ================= */
.pbar {
  position:fixed; top:0; left:0; right:0; z-index:80; display:flex; align-items:center;
  justify-content:space-between; padding:1rem clamp(1.2rem,4vw,2.6rem);
  background:color-mix(in srgb, var(--white) 88%, transparent); backdrop-filter:blur(10px);
}
.pbar__back { display:flex; align-items:center; gap:0.4rem; color:var(--black); text-decoration:none; font-weight:700; font-size:0.9rem; flex:1; }
/* the chapter's own NEU name, centred in the bar */
.pbar__name {
  flex:0 0 auto; font-weight:700; font-size:1.15rem; letter-spacing:0.02em;
  color:var(--blue); text-align:center;
}
.pbar__logo { height:40px; flex:1; object-fit:contain; object-position:right; }

/* -- footage pillars: reuse the cinematic frame-scrub three-beat scene -- */
.pintro { min-height:100vh; display:flex; flex-direction:column; justify-content:center; padding:7rem clamp(1.4rem,6vw,5rem) 3rem; background:var(--black); color:var(--white); }
.pintro--compact { min-height:auto; padding:6.4rem clamp(1.4rem,6vw,5rem) 1.6rem; }
.pintro__role { color:var(--blue); font-weight:700; letter-spacing:0.1em; text-transform:uppercase; font-size:0.82rem; margin-bottom:0.6rem; }
.pintro h1 { font-size:clamp(2.2rem,5vw,3.6rem); margin-bottom:1rem; }
.pintro__meta { display:flex; gap:2.4rem; flex-wrap:wrap; margin-top:2rem; font-size:0.88rem; opacity:0.8; max-width:44rem; }
.pintro__meta strong { display:block; color:var(--blue); font-size:0.75rem; letter-spacing:0.08em; text-transform:uppercase; margin-bottom:0.3rem; opacity:1; }

.scene { position:relative; background:var(--black); color:var(--white); }
.scene__stage { position:relative; height:100vh; overflow:hidden; }
.seq-canvas { position:absolute; inset:0; width:100%; height:100%; display:block; }
.seq-loading { position:absolute; inset:0; display:grid; place-items:center; background:var(--black); z-index:3; transition:opacity 0.4s ease; }
.seq-loading.done { opacity:0; pointer-events:none; }
.seq-loading__label { font-size:0.8rem; letter-spacing:0.2em; color:var(--white); opacity:0.55; }
.scene__copy { position:absolute; left:0; right:0; bottom:0; z-index:4; padding:2rem clamp(1.4rem,6vw,4rem) 2.6rem; background:linear-gradient(transparent, rgba(10,2,3,0.72)); min-height:44vh; }
.scene__domain { font-weight:700; font-size:clamp(1.5rem,3.6vw,2.4rem); letter-spacing:-0.01em; margin-bottom:0.5rem; }
.scene__beats { position:relative; min-height:5.2rem; }
.scene__beat { position:absolute; inset:0 auto auto 0; max-width:40rem; font-size:clamp(0.92rem,1.9vw,1.06rem); opacity:0; }
.phandoff { background:var(--black); color:var(--white); text-align:center; padding:clamp(5.5rem,18vh,10rem) 1.4rem; }
.phandoff span { display:inline-block; max-width:34rem; font-size:clamp(1.15rem,2.6vw,1.6rem); line-height:1.45; font-weight:700; opacity:0.92; }

/* -- non-footage pillars: scroll-pinned text reveal -- */
.preveal { min-height:100vh; display:flex; flex-direction:column; justify-content:center; padding:clamp(7rem,16vh,10rem) clamp(1.4rem,6vw,6rem) clamp(4rem,10vh,6rem); }
.preveal__role { color:var(--blue); font-weight:700; letter-spacing:0.14em; text-transform:uppercase; font-size:0.82rem; margin-bottom:1.1rem; }
.preveal h1 { font-size:clamp(2.4rem,5.4vw,4rem); line-height:1.1; letter-spacing:-0.025em; margin-bottom:1.6rem; max-width:16ch; }
.preveal__body { font-size:clamp(1.05rem,1.7vw,1.3rem); line-height:1.7; max-width:38rem; opacity:0.78; margin-bottom:clamp(2.8rem,6vw,4.4rem); }
.preveal__points { list-style:none; display:grid; gap:1.6rem; max-width:40rem; }
.preveal__points li { border-left:3px solid var(--blue); padding:0.2rem 0 0.2rem 1.4rem; opacity:0; transform:translateY(16px); font-size:1rem; line-height:1.65; }
.preveal__meta { display:flex; gap:3rem; flex-wrap:wrap; margin-top:clamp(2.8rem,6vw,4rem); font-size:0.85rem; opacity:0.75; }
.preveal__meta strong { display:block; color:var(--blue); font-size:0.72rem; letter-spacing:0.08em; text-transform:uppercase; margin-bottom:0.3rem; opacity:1; }

/* ---- pillar content blocks (brochure-depth sections) ----
   Spacing scale follows the notebooklm.google rhythm: tall section padding,
   a short measure for reading, and one generous gap between the words and
   whatever the section is showing. White space is the layout, not a leftover. */
:root {
  --blk-y:clamp(4.6rem,13vh,8.5rem);      /* section top/bottom breathing room */
  --blk-x:clamp(1.4rem,6vw,4rem);
  --blk-gap:clamp(1.5rem,3vw,2.3rem);     /* between cards in a grid */
  --blk-rest:clamp(2.6rem,5.5vw,4.2rem);  /* between the lead and the content */
}
.blk { padding:var(--blk-y) var(--blk-x); background:var(--white); color:var(--black); }
.blk--dark { background:var(--black); color:var(--white); }
.blk--cta { background:var(--blue); color:var(--white); }
.blk__wrap { max-width:66rem; margin:0 auto; }
.blk__h { font-size:clamp(1.8rem,3.9vw,3rem); line-height:1.14; letter-spacing:-0.02em; margin-bottom:1.4rem; max-width:26ch; }
.blk__h em { font-style:normal; color:var(--blue); }
.blk--dark .blk__h em, .blk--cta .blk__h em { color:#8ec5ff; }
.blk__lead { font-size:clamp(1.02rem,1.7vw,1.2rem); line-height:1.72; opacity:0.72; max-width:38rem; margin-bottom:var(--blk-rest); }
.blk--dark .blk__lead, .blk--cta .blk__lead { opacity:0.8; }
.blk .kicker { margin-bottom:1.1rem; }
.blk--dark .kicker, .blk--cta .kicker { color:#8ec5ff; }
/* a heading with no lead under it still needs the same rest before content */
.blk__h + .probs, .blk__h + .steps, .blk__h + .uses, .blk__h + .caps, .blk__h + .statrow { margin-top:var(--blk-rest); }

/* a statement is a pause — centre it and let the margins do the talking */
.blk--statement { padding-top:calc(var(--blk-y) * 1.15); padding-bottom:calc(var(--blk-y) * 1.15); }
.blk--statement .blk__wrap { max-width:46rem; text-align:center; }
.blk--statement .blk__h { max-width:none; margin-left:auto; margin-right:auto; }
.blk--statement .blk__lead { max-width:36rem; margin-left:auto; margin-right:auto; margin-bottom:0; }

/* stat row — 3D / 0 / Real-Time */
.statrow { list-style:none; display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:var(--blk-gap); margin-top:var(--blk-rest); }
.statrow li { border:1px solid rgba(255,255,255,0.16); border-radius:22px; padding:2.4rem 1.4rem; text-align:center; background:rgba(255,255,255,0.04); }
.statrow__big { display:block; font-size:clamp(2.1rem,4.4vw,3.1rem); font-weight:700; color:#8ec5ff; line-height:1; letter-spacing:-0.02em; }
.statrow__label { display:block; margin-top:0.9rem; font-size:0.88rem; line-height:1.55; opacity:0.75; }

/* numbered problems */
.probs { list-style:none; display:grid; gap:var(--blk-gap); }
.prob { display:flex; gap:1.5rem; align-items:flex-start; border:1px solid color-mix(in srgb, var(--black) 10%, var(--white)); border-radius:22px; padding:1.9rem 2.1rem; background:var(--white); box-shadow:0 16px 34px -28px rgba(10,2,3,0.3); }
.prob__n { font-weight:700; font-size:1.1rem; color:var(--blue); flex:none; min-width:2rem; }
.prob h3 { font-size:1.06rem; margin-bottom:0.5rem; }
.prob p { font-size:0.94rem; line-height:1.68; opacity:0.7; }

/* capability pair */
.caps { display:grid; grid-template-columns:repeat(auto-fit,minmax(250px,1fr)); gap:var(--blk-gap); }
.cap { border:1px solid rgba(255,255,255,0.16); border-radius:22px; padding:2rem 1.9rem; background:rgba(255,255,255,0.04); }
.cap h3 { color:#8ec5ff; font-size:1.06rem; margin-bottom:0.6rem; }
.cap p { font-size:0.92rem; line-height:1.68; opacity:0.75; }
.caps__pill { display:inline-block; margin-top:var(--blk-rest); border:1px solid rgba(255,255,255,0.3); border-radius:999px; padding:0.6rem 1.4rem; font-weight:700; font-size:0.9rem; }

/* process steps */
.steps { list-style:none; display:grid; gap:1.1rem; counter-reset:s; }
.step { display:flex; gap:1.4rem; align-items:flex-start; border-left:3px solid var(--blue); border-radius:0 20px 20px 0; padding:1.6rem 1.9rem; background:var(--blue-pale); }
.step__n { font-weight:700; color:var(--white); background:var(--blue); width:1.9rem; height:1.9rem; border-radius:50%; display:grid; place-items:center; flex:none; font-size:0.9rem; }
.step h3 { font-size:1.02rem; margin-bottom:0.4rem; }
.step p { font-size:0.92rem; line-height:1.68; opacity:0.72; }

/* use-case grid */
.uses { display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:var(--blk-gap); }
.use { border:1px solid color-mix(in srgb, var(--black) 10%, var(--white)); border-radius:24px; padding:2rem 1.9rem; background:var(--white); box-shadow:0 18px 38px -30px rgba(10,2,3,0.32); transition:transform 0.25s ease, box-shadow 0.25s ease; }
.use:hover { transform:translateY(-4px); box-shadow:0 24px 44px -26px rgba(10,2,3,0.34); }
.use h3 { color:var(--blue); font-size:1.08rem; margin-bottom:0.6rem; }
.use p { font-size:0.94rem; line-height:1.68; opacity:0.72; }

/* ---- hover glow on every box, site-wide ----
   A travelling neon ring (masked conic gradient) plus an ambient bloom —
   the same treatment the NEUStory cards use, applied consistently. */
.prob, .cap, .use, .step, .statrow li, .pillar-card, .news-card, .teamrow {
  position:relative;
  transition:transform 0.25s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}
.prob::after, .cap::after, .use::after, .step::after, .statrow li::after,
.pillar-card::after, .news-card::after {
  content:''; position:absolute; inset:0; border-radius:inherit;
  padding:2px; box-sizing:border-box; pointer-events:none; z-index:2;
  background:conic-gradient(from var(--laser-angle, 0deg),
    var(--blue), color-mix(in srgb, var(--blue) 55%, var(--white)) 25%,
    var(--white) 50%, color-mix(in srgb, var(--blue) 55%, var(--white)) 75%,
    var(--blue) 100%);
  filter:drop-shadow(0 0 5px var(--blue)) drop-shadow(0 0 10px color-mix(in srgb, var(--blue) 70%, transparent));
  -webkit-mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
  opacity:0; transition:opacity 0.3s ease;
}
.prob:hover::after, .cap:hover::after, .use:hover::after, .step:hover::after,
.statrow li:hover::after, .pillar-card:hover::after, .news-card:hover::after {
  opacity:1; animation:laser-spin 3s linear infinite;
}
.prob:hover, .cap:hover, .use:hover, .step:hover, .statrow li:hover,
.pillar-card:hover, .news-card:hover {
  transform:translateY(-3px);
  box-shadow:0 0 30px 5px color-mix(in srgb, var(--blue) 42%, transparent);
}
@media (prefers-reduced-motion:reduce) {
  .prob:hover::after, .cap:hover::after, .use:hover::after, .step:hover::after,
  .statrow li:hover::after, .pillar-card:hover::after, .news-card:hover::after { animation:none; }
}

/* ---- NEUStory news & gallery page ---- */
.newshead { padding-top:calc(4.5rem + var(--blk-y)); }  /* clears the fixed .pbar */
.newshead .blk__lead { margin-bottom:0; }
.newsgal { padding-top:clamp(3rem,7vh,4.5rem); }
.galfilter { display:flex; gap:0.7rem; flex-wrap:wrap; margin-bottom:var(--blk-rest); }
.galfilter a {
  display:inline-flex; align-items:center; gap:0.45rem; text-decoration:none;
  border:1.5px solid color-mix(in srgb, var(--black) 14%, var(--white));
  border-radius:999px; padding:0.45rem 1rem; font-size:0.86rem; font-weight:700;
  color:var(--black); transition:all 0.2s ease;
}
.galfilter a span { font-size:0.72rem; opacity:0.55; }
.galfilter a:hover { border-color:var(--blue); color:var(--blue); }
.galfilter a.is-on { background:var(--blue); border-color:var(--blue); color:var(--white); }
.galfilter a.is-on span { opacity:0.8; }

.gal { list-style:none; display:grid; grid-template-columns:repeat(auto-fill,minmax(290px,1fr)); gap:var(--blk-gap); }
.galcard {
  position:relative; border:1px solid color-mix(in srgb, var(--black) 9%, var(--white));
  border-radius:20px; overflow:hidden; background:var(--white);
  box-shadow:0 20px 40px -28px rgba(10,2,3,0.3);
  transition:transform 0.25s ease, box-shadow 0.3s ease, border-color 0.3s ease;
  display:flex; flex-direction:column;
}
.galcard::after {
  content:''; position:absolute; inset:0; border-radius:inherit; padding:3px;
  box-sizing:border-box; pointer-events:none; z-index:2;
  background:conic-gradient(from var(--laser-angle, 0deg),
    var(--blue), color-mix(in srgb, var(--blue) 55%, var(--white)) 25%,
    var(--white) 50%, color-mix(in srgb, var(--blue) 55%, var(--white)) 75%, var(--blue) 100%);
  filter:drop-shadow(0 0 5px var(--blue)) drop-shadow(0 0 10px color-mix(in srgb, var(--blue) 70%, transparent));
  -webkit-mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
  opacity:0; transition:opacity 0.3s ease;
}
.galcard:hover::after { opacity:1; animation:laser-spin 3s linear infinite; }
.galcard:hover { transform:translateY(-5px); box-shadow:0 0 32px 6px color-mix(in srgb, var(--blue) 42%, transparent); }
.galcard__media { aspect-ratio:4/3; overflow:hidden; background:var(--blue-pale); }
.galcard__media img { width:100%; height:100%; object-fit:cover; object-position:50% 20%; display:block; transition:transform 0.5s ease; }
.galcard:hover .galcard__media img { transform:scale(1.05); }
.galcard__media--none { display:grid; place-items:center; background:linear-gradient(140deg,#0a2036,#14385f); }
.galcard__media--none span { color:var(--white); font-weight:700; font-size:1.5rem; letter-spacing:0.1em; opacity:0.6; }
.galcard__body { padding:1.7rem 1.8rem 1.9rem; display:flex; flex-direction:column; gap:0.55rem; }
.galcard__meta { font-size:0.76rem; opacity:0.7; }
.galcard__pillar { color:var(--blue); font-weight:700; }
.galcard h3 { font-size:1.06rem; line-height:1.32; }
.galcard__text { font-size:0.92rem; line-height:1.68; opacity:0.72; }
.galcard__partner { font-size:0.82rem; opacity:0.62; margin-top:0.2rem; }

/* ---- orbit cards (sections 3 and 4) ----
   Dr. KC asked for rounded squares instead of circles, each carrying a
   picture, a short title and a short explanation — so a staff member can
   pitch the card itself rather than having to know what a circle stands for. */
.orbit__node--card { width:clamp(11rem,17vw,14.5rem); }
.ocard {
  display:block; border-radius:22px; overflow:hidden; position:relative;
  background:var(--white); color:var(--black); text-align:left;
  box-shadow:0 22px 46px -26px rgba(10,2,3,0.5);
  transition:box-shadow 0.3s ease;
}
.ocard__media { display:block; aspect-ratio:4/3; overflow:hidden; background:var(--blue-pale); }
.ocard__media img { width:100%; height:100%; object-fit:cover; display:block; }
.ocard__body { display:block; padding:0.85rem 0.95rem 1rem; }
.ocard__body strong { display:block; font-size:0.98rem; letter-spacing:-0.01em; margin-bottom:0.2rem; }
.ocard__body em { display:block; font-style:normal; font-size:0.78rem; line-height:1.45; opacity:0.68; }

/* the pulse that says "this one can be pressed" — front card only, so the
   ring doesn't turn into a light show */
.ocard--pulse::after {
  content:''; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  box-shadow:0 0 0 0 color-mix(in srgb, var(--white) 85%, transparent);
  opacity:0;
}
.orbit__node.is-front .ocard--pulse::after { opacity:1; animation:ocard-pulse 2.4s ease-out infinite; }
@keyframes ocard-pulse {
  0%   { box-shadow:0 0 0 0 color-mix(in srgb, var(--white) 80%, transparent); }
  70%  { box-shadow:0 0 0 14px color-mix(in srgb, var(--white) 0%, transparent); }
  100% { box-shadow:0 0 0 0 color-mix(in srgb, var(--white) 0%, transparent); }
}
.orbit__node.is-front .ocard { box-shadow:0 26px 60px -22px rgba(10,2,3,0.6); }
.orbit__node--card a { text-decoration:none; display:block; }
.orbit__node--card a:hover .ocard { box-shadow:0 0 34px 6px color-mix(in srgb, var(--white) 45%, transparent); }
@media (prefers-reduced-motion:reduce) { .ocard--pulse::after { animation:none !important; } }

/* a way out of the section for someone who wants the detail */
.sectmore {
  position:absolute; right:clamp(1.2rem,4vw,3rem); bottom:clamp(1.4rem,4vh,2.4rem); z-index:4;
  color:var(--white); text-decoration:none; font-weight:700; font-size:0.88rem;
  border:1px solid rgba(255,255,255,0.4); border-radius:999px; padding:0.55rem 1.2rem;
  transition:background 0.2s ease, border-color 0.2s ease;
}
.sectmore:hover { background:var(--blue); border-color:var(--blue); }

/* section 1's bottom-right button — the way out of the idle loop into proof */
.herowatch {
  position:absolute; right:clamp(1.2rem,4vw,3rem); bottom:clamp(1.6rem,5vh,3rem); z-index:3;
  display:flex; align-items:center; gap:0.9rem; text-decoration:none;
  padding:0.7rem 1.3rem 0.7rem 0.7rem; border-radius:999px;
  background:color-mix(in srgb, var(--white) 14%, transparent);
  border:1px solid rgba(255,255,255,0.4); color:var(--white);
  backdrop-filter:blur(10px);
  transition:background 0.25s ease, transform 0.25s ease, border-color 0.25s ease;
}
.herowatch:hover { background:var(--blue); border-color:var(--blue); transform:translateY(-3px); }
.herowatch__play {
  width:2.4rem; height:2.4rem; border-radius:50%; flex:none;
  background:var(--white); color:var(--blue); display:grid; place-items:center;
}
.herowatch__play svg { width:1.1rem; height:1.1rem; margin-left:2px; }
.herowatch__txt { display:flex; flex-direction:column; line-height:1.25; }
.herowatch__txt strong { font-size:0.92rem; }
.herowatch__txt em { font-style:normal; font-size:0.76rem; opacity:0.8; }

/* ---- the logo button + its credentials panel ----
   Dr. KC's idea: the round blue mark in the bar is a BUTTON. A slow pulse
   tells a first-time viewer that, without a label. Pressing it drops NEUON's
   certifications and awards, from anywhere on any page, at any point. */
.nav__brand--btn { border:none; background:none; padding:0; cursor:pointer; }
.nav__brand--btn.is-open .nav__radar i { animation:none; opacity:0; }

/* The panel is a CIRCLE that opens from behind the disc, exactly as Dr. KC
   drew it — capsule bar, blue disc riding on top of it, second round circle
   dropping out of it. The nav sits at z-index 80, so everything here stays
   below that and the disc keeps floating over the circle it opened. */
.certwrap { position:fixed; inset:0; z-index:70; }
.certwrap[hidden] { display:none; }
.certwrap__scrim {
  position:absolute; inset:0;
  background:color-mix(in srgb, var(--black) 55%, transparent);
  backdrop-filter:blur(6px);
  animation:cert-fade 0.3s ease;
}
@keyframes cert-fade { from { opacity:0; } }

/* radar waves rolling out of the disc — the button visibly "fires" */
.certwave {
  /* --cert-x / --cert-y are measured from the disc itself by certpanel.js,
     because the pill is not symmetrical and the disc is off viewport-centre */
  position:absolute; left:var(--cert-x,50%); top:var(--cert-y,3.5rem);
  transform:translate(-50%,-50%); pointer-events:none;
}
.certwave i {
  position:absolute; left:50%; top:50%; width:5.4rem; height:5.4rem; margin:-2.7rem 0 0 -2.7rem;
  border:2px solid var(--white); border-radius:50%; opacity:0;
  animation:cert-ping 2.4s ease-out infinite;
}
.certwave i:nth-child(2) { animation-delay:0.8s; }
.certwave i:nth-child(3) { animation-delay:1.6s; }
@keyframes cert-ping {
  0%   { transform:scale(0.7); opacity:0.75; }
  100% { transform:scale(5.5); opacity:0; }
}

/* The circle is centred ON the blue disc and grows out from behind it, so its
   top half disappears up behind the bar and only the bottom half is ever
   seen — the dome in Dr. KC's slide. All content therefore lives in the
   lower half. */
.certdisc {
  position:absolute; left:var(--cert-x,50%); top:var(--cert-y,3.5rem);
  transform:translate(-50%,-50%);
  width:min(58rem,96vw); aspect-ratio:1; border-radius:50%;
  background:var(--white); color:var(--black);
  box-shadow:0 40px 90px -20px rgba(10,2,3,0.45);
  transform-origin:center center;
  animation:cert-open 0.45s cubic-bezier(0.2,0.9,0.3,1.3);
}
@keyframes cert-open { from { opacity:0; transform:translate(-50%,-50%) scale(0.12); } }
@media (prefers-reduced-motion:reduce) {
  .certdisc, .certwrap__scrim { animation:none; }
  .certwave i { animation:none; opacity:0; }
}

/* Everything sits in the lower half — the part of the circle you can see.
   The kicker clears the blue disc, then the logos spin below it. */
/* starts below the blue disc — the disc hangs into the top of the circle, so
   anything above this line would be covered by it */
/* The dome is a full circle centred on the blue disc, so only its lower half
   is ever on screen: from 50% to 100% of its height. The middle of THAT is
   75%, which is where the ring belongs now the graph ball has gone. */
.certdisc__in {
  /* 72.5%, not 75%: the ring's depth scaling makes the front logo the tallest
     and it hangs lower than the ones behind, so the visual centre sits a little
     below the container's. Measured at 25px on a 928px dome. */
  position:absolute; top:72.5%; left:50%; transform:translate(-50%,-50%);
  width:86%; display:flex; flex-direction:column; align-items:center;
  gap:0.3rem; text-align:center;
}
.certdisc__kicker { font-weight:700; letter-spacing:0.13em; text-transform:uppercase; font-size:0.68rem; color:var(--blue); }

/* the credentials ring — same engine as sections 3 and 4, sized to sit
   inside the visible half of the dome */
.orbit--cert {
  --orbit-rx:150; --orbit-ry:30; --orbit-min-scale:0.55;
  width:100%; height:6.4rem; margin:0.1rem 0 0;
}
.orbit--cert .orbit__node { width:6.6rem; }
.orbit--cert .orbit__node a, .orbit--cert .clogo-wrap {
  display:flex; flex-direction:column; align-items:center; gap:0.4rem;
  text-decoration:none; color:var(--black);
}
.clogo {
  display:grid; place-items:center; width:6.4rem; height:4rem;
  border-radius:14px; background:var(--white);
  transition:transform 0.25s ease, box-shadow 0.25s ease;
}
.clogo img { max-width:100%; max-height:100%; width:auto; height:auto; object-fit:contain; display:block; }
.orbit--cert .orbit__node a:hover .clogo {
  transform:translateY(-3px);
  box-shadow:0 10px 26px -10px color-mix(in srgb, var(--blue) 70%, transparent);
}
.clogo__name {
  font-size:0.66rem; font-weight:700; line-height:1.25; opacity:0;
  transition:opacity 0.25s ease; max-width:7.2rem;
}
.clogo__name em { display:block; font-style:normal; font-weight:400; font-size:0.6rem; opacity:0.65; margin-top:0.1rem; }
/* only the card at the front is legible enough to bother labelling */
.orbit--cert .orbit__node.is-front .clogo__name { opacity:1; }

/* a plain round play button — the wording lives on the arc instead */
.certdisc__more {
  display:grid; place-items:center; width:2.6rem; height:2.6rem; border-radius:50%;
  margin:0.4rem auto 0; border:2px solid var(--blue); color:var(--blue);
  text-decoration:none; transition:background 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.certdisc__more svg { width:1.05rem; height:1.05rem; margin-left:2px; }
.certdisc__more:hover { background:var(--blue); color:var(--white); transform:scale(1.1); }

/* close sits just inside the dome's lower-right curve */
.certdisc__close {
  position:absolute; top:66%; right:13%; width:2rem; height:2rem;
  border:none; border-radius:50%; cursor:pointer; font-size:0.9rem;
  background:color-mix(in srgb, var(--black) 7%, var(--white)); color:var(--black);
}
.certdisc__close:hover { background:var(--blue); color:var(--white); }

/* the disc keeps pulsing while open so it still reads as the live control */
.nav__brand--btn.is-open { z-index:2; }

@media (max-width:640px) {
  .certdisc { width:150vw; }        /* wider than the screen — dome fills it */
  .certdisc__in { width:74%; gap:0.3rem; }
  .orbit--cert { --orbit-rx:112; --orbit-ry:26; height:9rem; }
  .orbit--cert .orbit__node { width:5.6rem; }
  .clogo { width:5rem; height:3.1rem; }
  .clogo__name { font-size:0.6rem; max-width:5.6rem; }
  .certdisc__close { right:26%; top:62%; }
}

/* ================= NEUON pack opening =================
   The mobile-game moment. Kept off the pitch path — it is the last thing
   before the footer, so a presenter never has to walk through it, but a
   visitor left alone with the screen has something to play with. */
/* THE DISC HANGS BELOW THE BAR.
   Every `.slide` measures its top clearance from var(--nav-disc) for that
   reason. The starter pack and the arcade are not slides, so they never got
   it, and the blue NEUON disc came to rest on top of "Young Innovator Starter
   Pack." — and on the arcade's heading under it. */
.pack {
  padding:calc(var(--nav-disc) + 1.6rem) var(--blk-x) var(--blk-y);
  background:var(--black); color:var(--white); text-align:center;
}
.pack__wrap { max-width:66rem; margin:0 auto; }
.pack .kicker { color:#8ec5ff; margin-bottom:1rem; }
.pack__h { font-size:clamp(1.7rem,3.6vw,2.7rem); letter-spacing:-0.02em; margin-bottom:0.9rem; }
.pack__h em { font-style:normal; color:#8ec5ff; }
.pack__lead { opacity:0.72; font-size:clamp(0.98rem,1.6vw,1.14rem); margin-bottom:var(--blk-rest); }
.pack__stage { position:relative; display:grid; place-items:center; min-height:26rem; }

/* ---- twelve packs on the shared ring ----
   Eight left visible gaps and read as loose cards; sixteen closes the ring
   into a proper carousel. */
.orbit--pack {
  --orbit-rx:340; --orbit-ry:58; --orbit-min-scale:0.34;
  height:24rem; cursor:grab; perspective:900px;
}
.orbit--pack:active { cursor:grabbing; }
.orbit--pack.is-gone { opacity:0; pointer-events:none; transition:opacity 0.35s ease; }
.orbit__node--pack { width:clamp(6.4rem,10vw,8.2rem); cursor:pointer; }

.ppack { display:block; transform-style:preserve-3d; }

/* ---- a pack that has been picked ----
   It comes to the centre, lifts, pulses, and can be turned by hand. The rest
   drop back and blur. The blur/opacity need !important because layout() in
   orbit.js writes those two properties inline on every frame. */
.orbit--pack.has-pick .orbit__node--pack:not(.is-picked) {
  filter:blur(3.5px) !important;
  opacity:0.32 !important;
}
.orbit__node--pack.is-picked { z-index:200 !important; }
.orbit__node--pack.is-picked .ppack {
  transform:scale(1.55) translateY(-10px) rotateY(var(--spin, 0deg));
  transition:transform 0.42s cubic-bezier(0.2,0.9,0.3,1.5);
  animation:pack-bounce 0.5s cubic-bezier(0.25,1.4,0.4,1);
}
/* while it is being turned by hand, follow the finger instead of easing */
.orbit__node--pack.is-picked .ppack.is-turning {
  transition:none; animation:none; cursor:grabbing;
}
@keyframes pack-bounce {
  0%   { transform:scale(1)    translateY(0)     rotateY(var(--spin, 0deg)); }
  55%  { transform:scale(1.68) translateY(-18px) rotateY(var(--spin, 0deg)); }
  100% { transform:scale(1.55) translateY(-10px) rotateY(var(--spin, 0deg)); }
}

/* the same radar language as the logo button, on the chosen pack */
.orbit__node--pack.is-picked .ppack__foil::after {
  content:''; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  box-shadow:0 0 0 0 color-mix(in srgb, var(--blue) 85%, var(--white));
  animation:pack-pulse 1.9s ease-out infinite;
}
@keyframes pack-pulse {
  0%   { box-shadow:0 0 0 0 color-mix(in srgb, var(--blue) 80%, var(--white)); }
  70%  { box-shadow:0 0 0 18px color-mix(in srgb, var(--blue) 0%, transparent); }
  100% { box-shadow:0 0 0 0 color-mix(in srgb, var(--blue) 0%, transparent); }
}

/* the reverse face, so turning it by hand shows a real back */
/* the reverse face gets the same foil as the front, so turning a pack round
   never reveals a flat dead side */
.ppack__back {
  position:absolute; inset:0; border-radius:14px; overflow:hidden;
  backface-visibility:hidden; transform:rotateY(180deg);
  background:
    radial-gradient(120% 80% at 70% 12%, color-mix(in srgb, var(--white) 30%, transparent), transparent 55%),
    linear-gradient(205deg, #0a63d6 0%, var(--blue) 42%, #0b3f8f 100%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,0.22);
  display:grid; place-items:center; padding:0.6rem;
}
.ppack__backword {
  color:var(--white); font-weight:700; text-align:center; line-height:1.35;
  font-size:clamp(0.58rem,1.05vw,0.74rem); letter-spacing:0.14em; text-transform:uppercase;
  opacity:0.92; text-shadow:0 2px 8px rgba(0,0,0,0.35);
}

.pack__pickhint { text-align:center; font-size:0.82rem; opacity:0.6; margin-top:0.4rem; letter-spacing:0.03em; }
.ppack__foil {
  backface-visibility:hidden;
  position:relative; width:100%; aspect-ratio:2/3; border-radius:14px; overflow:hidden;
  background:
    radial-gradient(120% 80% at 30% 12%, color-mix(in srgb, var(--white) 34%, transparent), transparent 55%),
    linear-gradient(155deg, #0a63d6 0%, var(--blue) 42%, #0b3f8f 100%);
  box-shadow:0 26px 54px -20px rgba(0,0,0,0.75), inset 0 0 0 1px rgba(255,255,255,0.22);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:0.6rem;
}
.orbit__node--pack.is-picked .ppack__foil {
  box-shadow:0 32px 64px -18px rgba(0,0,0,0.8), 0 0 34px -4px color-mix(in srgb, var(--blue) 70%, transparent),
             inset 0 0 0 1px rgba(255,255,255,0.3);
}
.ppack__mark { width:48%; height:auto; opacity:0.95; }
.ppack__word { font-weight:700; letter-spacing:0.3em; font-size:0.6rem; opacity:0.7; padding-left:0.3em; }

.ppack__shine {
  position:absolute; inset:-40% -120%; pointer-events:none;
  background:linear-gradient(74deg, transparent 42%, rgba(255,255,255,0.45) 50%, transparent 58%);
  animation:pack-shine 4.5s ease-in-out infinite;
}
@keyframes pack-shine { 0%,100% { transform:translateX(-30%); } 50% { transform:translateX(30%); } }

/* ---- the glowing tear strip: the only way in ---- */
.ppack__tear {
  pointer-events:none;
  position:absolute; left:0; right:0; top:16%; height:1.7rem;
  display:grid; place-items:center; cursor:ew-resize; touch-action:none;
  opacity:0; transition:opacity 0.3s ease;
}
.orbit__node--pack.is-picked .ppack__tear { opacity:1; pointer-events:auto; }
.ppack__back .ppack__tear { top:16%; }
.ppack__glow {
  position:absolute; left:0; right:0; top:50%; height:3px; transform:translateY(-50%);
  border-radius:3px; overflow:hidden;
  background:color-mix(in srgb, var(--white) 45%, transparent);
  box-shadow:0 0 8px 1px color-mix(in srgb, var(--white) 60%, transparent),
             0 0 18px 3px color-mix(in srgb, var(--blue) 80%, var(--white));
  transform:translateY(-50%) scaleY(calc(1 + var(--pull, 0) * 2.6));
}
/* the highlight that runs along the line, showing which way to swipe */
.ppack__glow::after {
  content:''; position:absolute; inset:0;
  background:linear-gradient(90deg, transparent 0%, var(--white) 45%, var(--white) 55%, transparent 100%);
  background-size:55% 100%; background-repeat:no-repeat;
  animation:tear-sweep 2.1s linear infinite;
}
@keyframes tear-sweep {
  0%   { background-position:-60% 0; }
  100% { background-position:170% 0; }
}
.ppack__tear.is-pulling .ppack__glow::after { animation:none; }
@keyframes tear-nudge { 0%,100% { margin-left:-3px; } 50% { margin-left:3px; } }

.orbit__node--pack.is-torn .ppack__foil { animation:pack-rip 0.52s ease-in forwards; }
@keyframes pack-rip {
  0%   { transform:scale(1); opacity:1; }
  35%  { transform:scale(1.07) rotate(-1.5deg); }
  100% { transform:scale(0.66) translateY(34px); opacity:0; }
}

.pack__card { position:absolute; inset:0; display:grid; place-content:center; justify-items:center; gap:1.2rem; }
/* an explicit display beats the hidden attribute — without this the card
   wrapper stays laid over the whole stage while "hidden", and every click on
   a pack lands on its link instead of the pack */
.pack__card[hidden] { display:none; }

@media (prefers-reduced-motion:reduce) {
  .ppack__glow::after { animation:none; }
}

/* ---- the card that comes out ---- */
.pack__card { display:grid; place-items:center; gap:1.2rem; }
.pcardx {
  position:relative; display:block; width:clamp(13rem,24vw,17rem);
  border-radius:20px; overflow:hidden; text-decoration:none;
  background:var(--white); color:var(--black); text-align:left;
  box-shadow:0 34px 70px -26px rgba(0,0,0,0.8), 0 0 0 3px color-mix(in srgb, var(--blue) 55%, transparent);
  transform:translateY(26px) scale(0.86) rotateX(12deg); opacity:0;
  transition:transform 0.55s cubic-bezier(0.2,0.9,0.3,1.3), opacity 0.4s ease, box-shadow 0.3s ease;
}
.pack__card.is-in .pcardx { transform:none; opacity:1; }
.pcardx:hover { box-shadow:0 34px 70px -22px rgba(0,0,0,0.85), 0 0 34px 6px color-mix(in srgb, var(--blue) 55%, transparent); }
.pcardx__holo {
  position:absolute; inset:0; z-index:2; pointer-events:none; mix-blend-mode:overlay;
  background:linear-gradient(115deg, transparent 30%, rgba(255,255,255,0.65) 45%, rgba(140,200,255,0.5) 55%, transparent 70%);
  background-size:250% 250%;
  animation:holo 3.4s linear infinite;
}
@keyframes holo { 0% { background-position:0% 0%; } 100% { background-position:250% 250%; } }
.pcardx__media { display:block; aspect-ratio:4/3; overflow:hidden; background:var(--blue-pale); }
.pcardx__media img { width:100%; height:100%; object-fit:cover; display:block; }
.pcardx__body { display:block; padding:1rem 1.1rem 0.4rem; }
.pcardx__kind { display:block; font-size:0.64rem; font-weight:700; letter-spacing:0.14em; text-transform:uppercase; color:var(--blue); margin-bottom:0.3rem; }
.pcardx__body strong { display:block; font-size:1.04rem; margin-bottom:0.25rem; }
.pcardx__body em { display:block; font-style:normal; font-size:0.82rem; line-height:1.5; opacity:0.68; }
.pcardx__go { display:block; padding:0.6rem 1.1rem 1.1rem; font-size:0.8rem; font-weight:700; color:var(--blue); }
.pack__again {
  background:none; border:1px solid rgba(255,255,255,0.35); color:var(--white);
  border-radius:999px; padding:0.5rem 1.3rem; font-weight:700; font-size:0.85rem; cursor:pointer;
  transition:background 0.2s ease, border-color 0.2s ease;
}
.pack__again:hover { background:var(--blue); border-color:var(--blue); }

/* ---- the zoom-through when a card is opened ---- */
.zoomer { position:fixed; inset:0; z-index:200; pointer-events:none; }
.zoomer[hidden] { display:none; }
.zoomer span {
  position:absolute; left:var(--zx,50%); top:var(--zy,50%);
  width:14rem; height:14rem; margin:-7rem 0 0 -7rem; border-radius:50%;
  background:var(--blue); transform:scale(0); opacity:0.9;
  transition:transform 0.46s cubic-bezier(0.5,0,0.75,0), opacity 0.46s ease;
}
.zoomer.is-on span { transform:scale(14); opacity:1; }

@media (prefers-reduced-motion:reduce) {
  .ppack__shine, .pcardx__holo { animation:none; }
  .pcardx { transition:none; transform:none; opacity:1; }
}

/* ---- projects carousel ----
   A full-bleed horizontal rail: the first card lines up with the section
   text, the last one runs off the right edge so it reads as "there's more".
   Scroll-snap does the work; the arrows and dots are progressive enhancement. */
.projects { padding-bottom:calc(var(--blk-y) * 0.7); }
.projects .blk__lead { margin-bottom:0; }

/* break out of the section's horizontal padding so the rail is full-bleed */
.prow { position:relative; margin:var(--blk-rest) calc(var(--blk-x) * -1) 0; }
.prow__track {
  list-style:none; display:flex; gap:var(--blk-gap);
  overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory; scroll-behavior:smooth;
  padding:0.6rem max(var(--blk-x), calc((100% - 66rem) / 2)) 1.6rem;
  scrollbar-width:none;
}
.prow__track::-webkit-scrollbar { display:none; }

.pcard { flex:0 0 clamp(15rem,25vw,19.5rem); scroll-snap-align:start; }
.pcard__in {
  position:relative; display:flex; flex-direction:column; height:100%;
  border:1px solid color-mix(in srgb, var(--black) 9%, var(--white));
  border-radius:24px; overflow:hidden; background:var(--white); color:var(--black);
  text-decoration:none; box-shadow:0 20px 40px -30px rgba(10,2,3,0.3);
  transition:transform 0.25s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}
.pcard__in::after {
  content:''; position:absolute; inset:0; border-radius:inherit; padding:2px;
  box-sizing:border-box; pointer-events:none; z-index:3;
  background:conic-gradient(from var(--laser-angle, 0deg),
    var(--blue), color-mix(in srgb, var(--blue) 55%, var(--white)) 25%,
    var(--white) 50%, color-mix(in srgb, var(--blue) 55%, var(--white)) 75%, var(--blue) 100%);
  filter:drop-shadow(0 0 5px var(--blue)) drop-shadow(0 0 10px color-mix(in srgb, var(--blue) 70%, transparent));
  -webkit-mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
  opacity:0; transition:opacity 0.3s ease;
}
.pcard__in:hover::after { opacity:1; animation:laser-spin 3s linear infinite; }
.pcard__in:hover { transform:translateY(-5px); box-shadow:0 0 32px 6px color-mix(in srgb, var(--blue) 40%, transparent); }

.pcard__media { position:relative; aspect-ratio:4/3; overflow:hidden; background:var(--blue-pale); }
.pcard__media img { width:100%; height:100%; object-fit:cover; display:block; transition:transform 0.5s ease; }
.pcard__in:hover .pcard__media img { transform:scale(1.05); }

.pcard__status {
  position:absolute; top:0.9rem; left:0.9rem; z-index:2;
  border-radius:999px; padding:0.3rem 0.75rem; font-size:0.68rem; font-weight:700;
  letter-spacing:0.08em; text-transform:uppercase;
  background:color-mix(in srgb, var(--white) 88%, transparent); color:var(--black);
  backdrop-filter:blur(8px); border:1px solid rgba(255,255,255,0.6);
}
.pcard__status--live { background:var(--blue); color:var(--white); border-color:transparent; }
.pcard__status--pilot { background:var(--black); color:var(--white); border-color:transparent; }

.pcard__body { padding:1.4rem 1.5rem 1.6rem; display:flex; flex-direction:column; gap:0.5rem; flex:1; }
.pcard__body h3 { font-size:1.1rem; letter-spacing:-0.01em; }
.pcard__body p { font-size:0.9rem; line-height:1.65; opacity:0.7; flex:1; }
.pcard__go { font-size:0.82rem; font-weight:700; color:var(--blue); margin-top:0.4rem; }
.pcard__go em { font-style:normal; display:inline-block; transition:transform 0.2s ease; }
.pcard__in:hover .pcard__go em { transform:translate(2px,-2px); }
.pcard__note { font-size:0.78rem; font-weight:700; opacity:0.45; margin-top:0.4rem; }

/* arrows — hidden until they have somewhere to go */
.prow__nav {
  position:absolute; top:calc(50% - 3rem); z-index:4;
  width:2.9rem; height:2.9rem; border-radius:50%; border:none; cursor:pointer;
  background:var(--white); color:var(--black);
  box-shadow:0 6px 20px -6px rgba(10,2,3,0.35);
  display:grid; place-items:center;
  transition:opacity 0.25s ease, transform 0.2s ease, background 0.2s ease;
}
.prow__nav svg { width:1.3rem; height:1.3rem; }
.prow__nav:hover { background:var(--blue); color:var(--white); transform:scale(1.08); }
.prow__nav--prev { left:clamp(0.6rem,2vw,1.4rem); }
.prow__nav--next { right:clamp(0.6rem,2vw,1.4rem); }
.prow__nav[disabled] { opacity:0; pointer-events:none; }

.prow__foot { display:flex; justify-content:flex-end; }
.prow__dots { display:flex; gap:0.4rem; align-items:center; }
.prow__dots button {
  width:0.5rem; height:0.5rem; border-radius:999px; border:none; cursor:pointer;
  background:color-mix(in srgb, var(--black) 18%, var(--white));
  transition:width 0.25s ease, background 0.25s ease; padding:0;
}
.prow__dots button.is-on { width:1.5rem; background:var(--black); }

/* dark sections keep the same rail, inverted */
.blk--dark .prow__nav { background:var(--white); color:var(--black); }
.blk--dark .prow__dots button { background:rgba(255,255,255,0.28); }
.blk--dark .prow__dots button.is-on { background:var(--white); }

/* full-bleed image band — the eye's rest between text sections */
.imgband { position:relative; margin:0; background:var(--black); overflow:hidden; }
.imgband img { display:block; width:100%; height:clamp(19rem,46vh,30rem); object-fit:cover; }
.imgband--tall img { height:clamp(24rem,64vh,40rem); }
.imgband figcaption {
  position:absolute; left:0; right:0; bottom:0; padding:2.4rem clamp(1.4rem,6vw,4rem) 1.4rem;
  background:linear-gradient(transparent, rgba(10,2,3,0.72));
  color:var(--white); font-size:0.88rem; font-weight:700; letter-spacing:0.02em;
}

/* CTA */
.ctaline { display:flex; gap:1.8rem; flex-wrap:wrap; margin-bottom:1.8rem; font-size:1.05rem; }
.ctaline a { color:var(--white); font-weight:700; text-decoration:none; border-bottom:2px solid rgba(255,255,255,0.5); }
.ctaline a:hover { border-color:var(--white); }
.certrow { list-style:none; display:flex; gap:0.7rem; flex-wrap:wrap; }
.certrow li { border:1px solid rgba(255,255,255,0.42); border-radius:999px; padding:0.32rem 0.85rem; font-size:0.76rem; font-weight:700; letter-spacing:0.04em; }

/* -- shared: NEUStory mini-feed at the bottom of every pillar page
   (same card style as the 4600 build — rounded, hover-glow, backed by
   the same Backstage database, filtered to this pillar) -- */
.pnews { padding:var(--blk-y) var(--blk-x); background:var(--white); }
.pnews > * { max-width:66rem; margin-left:auto; margin-right:auto; }
.pnews .kicker { text-align:left; margin-bottom:1.1rem; }
.pnews .slide__title { color:var(--black); margin-bottom:0.4rem; letter-spacing:-0.02em; }
.feed { list-style:none; display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:var(--blk-gap); margin-top:var(--blk-rest); }
.feed__card {
  position:relative; border:1px solid color-mix(in srgb, var(--black) 8%, var(--white));
  border-radius:20px; overflow:hidden; padding:1.6rem; background:var(--white); color:var(--black);
  box-shadow:0 20px 40px -26px rgba(10,2,3,0.28);
  transition:transform 0.25s ease, box-shadow 0.25s ease, border-color 0.5s ease;
}
.feed__card:hover { transform:translateY(-4px); }
.feed__card.corner-lit {
  border-color:var(--blue);
  box-shadow:0 10px 30px -14px color-mix(in srgb, var(--blue) 35%, transparent), 0 0 22px color-mix(in srgb, var(--blue) 25%, transparent);
}
.feed__card::after {
  content:''; position:absolute; inset:0; border-radius:inherit; padding:4px; box-sizing:border-box;
  background:conic-gradient(from var(--laser-angle, 0deg), var(--blue), color-mix(in srgb, var(--blue) 55%, var(--white)) 25%,
    var(--white) 50%, color-mix(in srgb, var(--blue) 55%, var(--white)) 75%, var(--blue) 100%);
  filter:drop-shadow(0 0 5px var(--blue)) drop-shadow(0 0 10px color-mix(in srgb, var(--blue) 70%, transparent));
  -webkit-mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
  opacity:0; transition:opacity 0.3s ease; pointer-events:none; z-index:2;
}
.feed__card:hover::after { opacity:1; animation:laser-spin 3s linear infinite; }
.feed__card:hover { box-shadow:0 0 30px 6px color-mix(in srgb, var(--blue) 45%, transparent); }
@property --laser-angle { syntax:'<angle>'; inherits:false; initial-value:0deg; }
@keyframes laser-spin { to { --laser-angle:360deg; } }
.feed__photo { width:calc(100% + 3.2rem); max-width:none; margin:-1.6rem -1.6rem 1.1rem; display:block; aspect-ratio:4/3; object-fit:cover; object-position:50% 20%; }
.feed__meta { font-size:0.78rem; opacity:0.75; margin-bottom:0.6rem; }
.feed__card h3 { font-size:1.02rem; margin-bottom:0.5rem; }
.feed__card p:last-child { font-size:0.88rem; opacity:0.85; }

/* -- shared: prev/next chapter bar, pinned to the bottom of the viewport so
   the next chapter is always one tap away without scrolling to the end -- */
:root { --pfoot-h:4.1rem; }
.pillar-page { padding-bottom:var(--pfoot-h); }
.pfoot {
  position:fixed; bottom:0; left:0; right:0; z-index:70;
  display:flex; justify-content:space-between; align-items:center; gap:0.6rem;
  height:var(--pfoot-h); padding:0 clamp(0.9rem,4vw,2.4rem);
  background:color-mix(in srgb, var(--black) 88%, transparent);
  backdrop-filter:blur(12px); border-top:1px solid rgba(255,255,255,0.14);
  color:var(--white);
}
.pfoot a {
  color:var(--white); text-decoration:none; font-weight:700; opacity:0.9;
  font-size:0.9rem; display:flex; align-items:center; gap:0.4rem;
  padding:0.5rem 0.7rem; border-radius:999px; transition:background 0.2s ease, opacity 0.2s ease;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:38vw;
}
.pfoot a:hover { opacity:1; background:rgba(255,255,255,0.12); }
.pfoot__home {
  color:var(--white) !important; background:var(--blue);
  flex:none; padding:0.5rem 1.1rem !important;
}
.pfoot__home:hover { background:#0a67d6; }

/* ---- responsive ---- */
@media (max-width:900px) {
  .nav__side { display:none; }   /* burger takes over — see the drawer */
  .nav__pill { padding:0.5rem 1rem; gap:0.8rem; }
  /* pinned to the left edge, mirroring the search button, so neither one
     crowds the circle in the middle */
  .nav__burger {
    display:flex; position:absolute; left:clamp(1rem,4vw,1.6rem);
    top:50%; transform:translateY(-50%);
  }
  .pbar__name { font-size:1rem; }
  .pbar__back span { display:none; }
  .orbit { --orbit-rx:132; --orbit-ry:82; --orbit-min-scale:0.3; height:26rem; }
  .orbit--sov { --orbit-rx:140; --orbit-ry:86; --orbit-min-scale:0.36; height:26rem; }
  .orbit__node, .orbit__disc { width:5.4rem; }
  .orbit__disc { height:5.4rem; }
  .orbit--sov .orbit__node { width:5.4rem; }
  .orbit--sov .orbit__disc { width:4.4rem; height:4.4rem; }
  .orbit__label { font-size:0.85rem; }
  .orbit__label em { display:none; }
  .orbit__hub .slide__title { font-size:1.7rem; }
  .orbit__hub--map { width:92vw; }
  .phase-row, .grain-row { grid-template-columns:repeat(2,1fr); }
  .family__row { flex-direction:column; text-align:center; }
  .rail { display:none; }
}

/* ---- short viewports (most laptops are ~720-800px tall) ----
   These slides are scroll-snapped and clip their overflow, so anything that
   doesn't fit is simply lost. The card rings are the tallest thing on the
   page, so they shrink first, then the supporting text. */
@media (max-height:860px) {
  /* still measured from the disc — it is what overlaps, not the bar */
  .slide { padding-top:calc(var(--nav-disc) + 0.8rem); padding-bottom:1.6rem; }
  .orbit--sov { --orbit-ry:80; --orbit-rx:360; height:23rem; }
  .orbit--how { --orbit-ry:88; --orbit-rx:400; height:25rem; }
  .orbit__node--card,
  .orbit--sov .orbit__node--card { width:10.5rem; }
  .ocard__body { padding:0.6rem 0.75rem 0.7rem; }
  .ocard__body strong { font-size:0.88rem; }
  .ocard__body em { font-size:0.72rem; }
  .sov__head { margin-bottom:0.4rem; }
  .compact-quote { padding:0.7rem 1rem; }
  .compact-quote h4 { font-size:0.7rem; }
  .compact-quote p { font-size:0.82rem; }
}

/* phones: keep the airy rhythm but stop it turning into dead scrolling */
@media (max-width:600px) {
  :root { --blk-y:clamp(3.4rem,9vh,5.4rem); --blk-rest:2.2rem; --blk-gap:1.1rem; }
  .prob, .cap, .use { padding:1.5rem 1.4rem; }
  .step { padding:1.3rem 1.4rem; }
  .statrow li { padding:1.9rem 1.2rem; }
  .galcard__body { padding:1.4rem 1.4rem 1.6rem; }
  /* touch swipes the rail — arrows would just cover the cards */
  .prow__nav { display:none; }
  .orbit--pack { --orbit-rx:150; --orbit-ry:34; height:17rem; }
  .orbit__node--pack { width:5rem; }
  .prow__foot { justify-content:center; }
}

/* pointers that can't hover (touch) don't get the arrows either */
@media (hover:none) { .prow__nav { display:none; } }

/* a credential parked at the centre by a click */
.orbit--cert .orbit__node { cursor:pointer; }
.orbit--cert .orbit__node.is-held .clogo {
  transform:translateY(-4px) scale(1.12);
  box-shadow:0 12px 30px -8px color-mix(in srgb, var(--blue) 75%, transparent);
}
.orbit--cert .orbit__node.is-held .clogo__name { opacity:1; }

/* ---- section 2: Dr. KC's diagram, shown whole ---- */
.slide--teach { padding:0; align-items:center; justify-content:center; background:#0b1b2e; }

/* ── SECTION 2, ONE STAGE AT A TIME ──
   The section is taller than the screen and the stage inside it is pinned, so
   the extra height is scroll to spend walking through the three stages rather
   than a wall of three columns arriving at once. Same shape as Section 1. */
/* 340vh, not 290: three quarters of the travel is spent stepping through the
   three stages and the last quarter is the hold at the end, so the section has
   to be tall enough to give each stage a screenful of scroll AND still have a
   pause left over. */
.slide--teach { min-height:340vh; overflow:clip; justify-content:flex-start; }
/* Long-winded for the same reason the film band is: `.studio > :not(...)`
   forces position:relative on every child of this section, and a plain
   `.teach__pin` lost to it — leaving the stage un-pinned and the whole
   stepping dead, with --sp stuck at 1. */
.slide.slide--teach.studio > .teach__pin,
.slide.slide--teach > .teach__pin {
  position:sticky; top:0; height:100vh; width:100%;
  /* `safe center` because centred content that is TALLER than the box
     overflows equally both ways — and the top way is under the nav disc. Safe
     falls back to starting at the padding edge the moment it would not fit,
     so the heading can never ride up under the mark. */
  display:flex; flex-direction:column; justify-content:safe center; align-items:center;
  /* The bottom padding is not spare room — it is the strip the three stage
     dots stand in. At 2rem the dots printed straight over "Chapter · Happening
     now · Published" and the line under it. The stage is centred in whatever
     is left, so giving the dots their own space lifts the content clear. */
  padding:calc(var(--nav-disc) + 1rem) clamp(1rem,4vw,3rem) 6.4rem;
  overflow:hidden;
}

/* The three columns stop being a row and become one stack, each taking the
   middle of the screen in turn. They stay in the layout — the film's palm is
   lined up against the ball in stage 2, and an element that has been display
   :none has no position to line anything up with. */
.teach__pin .teach3 {
  position:relative; display:block; width:min(46rem,92vw); flex:none;
}
.teach__pin .teach3__col {
  position:absolute; left:50%; top:50%;
  width:100%; transform:translate(-50%,-50%) scale(0.96);
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity 0.4s ease, transform 0.4s ease, visibility 0s linear 0.4s;
}
.teach__pin .teach3__col.is-on {
  opacity:1; visibility:visible; pointer-events:auto;
  transform:translate(-50%,-50%) scale(1);
  transition:opacity 0.4s ease, transform 0.4s ease, visibility 0s;
}
/* the stack needs a height of its own, since every column is out of flow */
.teach__pin .teach3 { min-height:clamp(20rem,52vh,30rem); }
/* A SHORT WINDOW has to give the stage less, or the heading plus the stage
   plus the dots' strip add up to more than the screen and the whole lot
   overflows the pin. The section used to have 160px of its own padding on top
   of the pin's, which hid this; that padding was what drew a line across the
   top of the section, so it is gone and the arithmetic has to work. */
@media (max-height:800px) { .teach__pin .teach3 { min-height:clamp(15rem,40vh,22rem); } }

/* the three inputs and the three results were columns; with a whole screen
   each they read better across */
.teach__pin .teach3__feeds { grid-template-columns:1fr 1fr; }
.teach__pin .teach3__results { grid-template-columns:1fr 1fr; }
/* A smaller ball buys room at BOTH ends, because the stage is centred: the
   stage heading drops away from the subtitle, and AI CORE with the legend and
   the line under it lift clear of the three dots. Dr KC asked for both. */
.teach__pin .teach3__brain { width:min(19rem,44vw); margin:0 auto; }
/* A SHORT WINDOW. The ball is the tallest thing in stage 2 and it is sized
   from viewport WIDTH, so on a wide, short window it is the piece that pushes
   the legend down onto the three dots. This has to sit AFTER the rule above,
   not in an earlier media query — a media query buys no specificity. */
@media (max-height:800px) { .teach__pin .teach3__brain { width:min(15rem,30vh); } }
/* and the step heading sits lower, off the subtitle above it */
.teach__pin .teach3__step { margin-top:0.9rem; }
/* AI CORE hugs the ball rather than floating under it */
.teach__pin .teach3__chip { margin-top:0.2rem; }
.teach__pin .teach3__note { margin-top:0.5rem; }

/* "1 RAW INPUT SIGNALS" over the middle of its own stage. It was aligned left
   because it used to head a column in a row of three; alone on the screen,
   left-aligned over a centred grid just looks like a mistake. */
.teach__pin .teach3__step { justify-content:center; }

/* THE CALL TO ACTION GOES TO THE SIDE.
   It sits at the foot of the section, which is exactly where the three stage
   dots are — the button and the dots were printed on top of each other. The
   dots stay in the middle, because they are the thing being stepped; the
   button moves out to the right, where nothing else is. */
.teach__pin .ctarow {
  position:absolute; right:clamp(1rem,4vw,3rem); bottom:2rem;
  margin-top:0; z-index:6;
}

/* which stage is showing, and a way to jump */
.teachnav {
  position:absolute; left:50%; transform:translateX(-50%); bottom:2.2rem;
  display:flex; gap:0.5rem; z-index:6;
}
.teachdot {
  width:2.1rem; height:2.1rem; border-radius:50%; cursor:pointer;
  border:1.5px solid rgba(255,255,255,0.22); background:rgba(8,19,31,0.6);
  color:var(--white); font:800 0.78rem 'Inter',sans-serif; line-height:1;
  display:grid; place-items:center;
  transition:background 0.16s ease, border-color 0.16s ease, transform 0.12s ease;
}
.teachdot:hover { transform:scale(1.08); border-color:rgba(255,255,255,0.5); }
.teachdot.is-on { background:var(--blue); border-color:var(--blue); }

/* A phone gets the SAME stepped stage. It was left as a plain stack on the
   theory that a phone already reads top to bottom one thing at a time — but
   three columns stacked in one screen's worth of section simply ran into each
   other, which is what it actually looked like. One at a time, pinned, is the
   fix on a phone for the same reason it is on a desktop; only the sizes
   change. */
@media (max-width:820px) {
  .teach__pin { padding:calc(var(--nav-disc) + 0.3rem) 1rem 0.6rem; }
  .teach__pin .teach3 { width:min(30rem,94vw); min-height:clamp(18rem,46vh,26rem); }
  .teach__pin .teach3__feeds { grid-template-columns:1fr 1fr; gap:0.45rem; }
  .teach__pin .teach3__results { grid-template-columns:1fr; gap:0.5rem; }
  .teach__pin .teach3__brain { width:min(15rem,58vw); }
  .teach__pin .teach3__res { padding:0.4rem 0.6rem; }
  .teach__pin .teach3__res em { font-size:0.72rem; line-height:1.28; }
  /* the gap the stage heading gets on a desktop is room a phone does not
     have — stage 3 is the tallest and it met the button */
  .teach__pin .teach3__step { font-size:0.8rem; margin-top:0; }
  .teachdot { width:1.9rem; height:1.9rem; }
  /* On a phone the button and the dots come back into the flow and simply sit
     under the stage. Pinned to the bottom edge they were fine for stages 1 and
     2 and collided with stage 3, which is half as tall again as the others —
     and a phone has no width to put the button beside the dots. The stage box
     is given the height of the TALLEST stage so the two of them do not jump up
     and down as the stages change. */
  .teach__pin { justify-content:flex-start; }
  .teach__pin .teach3 { min-height:27.5rem; }
  .teach__pin .ctarow {
    position:static; transform:none; margin:0.6rem auto 0; justify-content:center;
  }
  .teachnav { position:static; transform:none; margin:0.5rem auto 0; }
}

/* ── the film behind "We Teach, It Learn" ──
   The same treatment as Section 1 and for the same reason: it is scrubbed by
   the scroll rather than played, so the boy and the robot move as far as
   somebody has moved and stop when they stop. Two things matter here and
   they pull against each other — the picture has to read, and three columns
   of text have to stay legible over it. Hence a dark plate and a heavy
   double scrim rather than a brighter film and a lighter wash. */
/* A FULL-WIDTH BAND, NOT A FILL. This section is taller than it is wide, so
   object-fit:cover cropped 60% of the frame's width away and took the boy —
   the whole point of the picture — with it. Full width shows the composition
   whole; scrollfilm.js sets --film-top so the robot's palm lands on the ball,
   and the edges are faded into the section's own colour so the band has no
   visible top and bottom. */
/* Written long, and it has to be. This section also carries `.studio`, and
   `.studio > :not(.studio__rig):not(.netball)` makes every child position
   :relative — three classes, so it beat a plain `.teach__bg` and left the
   band offset from its static position instead of placed against the
   section. These two selectors exist to outrank it. */
.slide.slide--teach.studio .teach__bg,
.slide.slide--teach .teach__bg {
  position:absolute; right:auto; z-index:0;
  left:var(--film-x, -160px); top:var(--film-top, 20%);
  /* wider than the section, so sliding it sideways to line the palm up on
     the ball can never pull a bare edge into view. scrollfilm.js knows this
     same number as PAD. */
  width:calc(100% + 320px); height:var(--film-h, auto); object-fit:cover;
  filter:brightness(0.52) contrast(1.05) saturate(1.1);
  pointer-events:none;
  -webkit-mask-image:linear-gradient(180deg, transparent 0%, #000 16%, #000 82%, transparent 100%);
          mask-image:linear-gradient(180deg, transparent 0%, #000 16%, #000 82%, transparent 100%);
}
.slide.slide--teach.studio .teach__scrim,
.slide.slide--teach .teach__scrim {
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    /* THE DARK BAND HAS TO OUTLAST THE HEADING.
       It used to fade to 40% by 22%, and the heading runs from 19.6% to 30.2%
       — so the words were on the lit part of the film while every other
       heading on the site sits on near-black. That, not the letters, is why it
       read grey. The band now holds full strength to 32% and lets go by 40%,
       which is below the subtitle and above the first stage. */
    linear-gradient(180deg, rgba(11,27,46,0.94) 0%, rgba(11,27,46,0.9) 32%,
                            rgba(11,27,46,0.4) 40%,
                            rgba(11,27,46,0.4) 66%, rgba(11,27,46,0.95) 100%),
    /* and a wash left and right, which is where the two columns of text are */
    linear-gradient(90deg, rgba(11,27,46,0.9) 0%, rgba(11,27,46,0.18) 30%,
                           rgba(11,27,46,0.18) 70%, rgba(11,27,46,0.9) 100%);
}
/* Nothing is needed to lift the section's own contents in front of the film:
   this section also carries `.studio`, and that already gives every child
   position:relative and z-index:2 further down this file. */
.teach__art { width:100%; height:100%; object-fit:contain; display:block; }

/* home button, mirroring the search button on the other side of the bar */
.nav__home {
  position:absolute; left:clamp(1.2rem,4vw,3rem); top:50%; transform:translateY(-50%);
  pointer-events:auto; width:2.8rem; height:2.8rem; border-radius:50%;
  background:var(--blue-pale); color:var(--blue);
  display:grid; place-items:center; text-decoration:none;
  transition:background 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.nav__home:hover { background:var(--blue); color:var(--white); transform:translateY(-50%) scale(1.06); }
@media (max-width:900px) { .nav__home { display:none; } }

/* the visible way back to the ring, under the swipe hint */
.pack__swap {
  display:block; margin:0.7rem auto 0;
  background:none; border:1px solid rgba(255,255,255,0.35); color:var(--white);
  border-radius:999px; padding:0.45rem 1.2rem; font-weight:700; font-size:0.82rem;
  cursor:pointer; transition:background 0.2s ease, border-color 0.2s ease;
}
.pack__swap:hover { background:var(--blue); border-color:var(--blue); }
.pack__swap[hidden] { display:none; }

/* ================= SECTION 1 · the reel =================
   3:4 cards tracking right and off the edge, over the hero background. The
   headline sits on top; hovering it opens a hole around the cursor. */
.slide--hero { justify-content:center; }
.reel {
  position:absolute; left:0; right:0; top:50%; transform:translateY(-50%);
  z-index:2; overflow:hidden; padding:2rem 0;
  -webkit-mask-image:linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image:linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.reel__track {
  display:flex; gap:clamp(1rem,2.4vw,2rem); width:max-content;
  animation:reel-run 48s linear infinite;
}
@keyframes reel-run { from { transform:translateX(-50%); } to { transform:translateX(0); } }
.reel.is-open .reel__track { animation-play-state:paused; }

.rcard {
  position:relative; flex:none; width:clamp(8rem,13vw,11.5rem); aspect-ratio:3/4;
  border:0; padding:0; cursor:pointer; border-radius:18px; overflow:hidden;
  background:color-mix(in srgb, var(--white) 8%, transparent);
  box-shadow:0 22px 46px -22px rgba(0,0,0,0.7), inset 0 0 0 1px rgba(255,255,255,0.18);
  transition:transform 0.3s ease, box-shadow 0.3s ease, filter 0.3s ease;
}
.rcard img { width:100%; height:100%; object-fit:cover; display:block; }
.rcard__tag {
  position:absolute; left:0; right:0; bottom:0; padding:1.6rem 0.7rem 0.6rem;
  background:linear-gradient(transparent, rgba(10,2,3,0.8));
  color:var(--white); font-weight:700; font-size:0.76rem; letter-spacing:0.02em;
}
.rcard:hover { transform:translateY(-6px); box-shadow:0 28px 56px -18px rgba(0,0,0,0.8), 0 0 26px -4px color-mix(in srgb, var(--blue) 75%, transparent), inset 0 0 0 1px rgba(255,255,255,0.35); }
.reel.is-open .rcard:not(.is-open) { filter:blur(3px); opacity:0.35; }

/* ---- the headline, with a torch hole that follows the cursor ---- */
.herotitle {
  position:relative; z-index:4; text-align:center; text-transform:uppercase;
  letter-spacing:-0.01em; max-width:min(46rem,90vw); margin:0 auto;
  text-shadow:0 4px 30px rgba(0,0,0,0.55);
  cursor:default;
}
.herotitle.is-lit {
  -webkit-mask-image:radial-gradient(circle var(--tr,110px) at var(--tx,50%) var(--ty,50%),
    transparent 0, transparent 55%, #000 100%);
          mask-image:radial-gradient(circle var(--tr,110px) at var(--tx,50%) var(--ty,50%),
    transparent 0, transparent 55%, #000 100%);
}

/* ---- the landscape panel a card opens into ---- */
/* 250, not 150: Section 1's chapter fan sits at 200, and a film opened FROM
   that fan was rendering behind it. Above the fan, below the unlock box. */
.reelopen { position:fixed; inset:0; z-index:250; display:grid; place-items:center; padding:1.2rem;
  background:color-mix(in srgb, var(--black) 62%, transparent); backdrop-filter:blur(8px); }
.reelopen[hidden] { display:none; }
.reelopen__panel {
  position:relative; width:min(64rem,94vw); aspect-ratio:16/7;
  border-radius:26px; overflow:hidden; background:var(--black);
  box-shadow:0 50px 100px -30px rgba(0,0,0,0.8);
  animation:reel-open 0.45s cubic-bezier(0.2,0.9,0.3,1.3);
}
@keyframes reel-open { from { opacity:0; transform:scale(0.82); } }
.reelopen__panel img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.reelopen__body {
  position:absolute; inset:auto 0 0 0; padding:clamp(1.4rem,4vw,2.6rem);
  background:linear-gradient(transparent, rgba(10,2,3,0.88)); color:var(--white);
}
.reelopen__kind { font-size:0.76rem; font-weight:700; letter-spacing:0.14em; text-transform:uppercase; color:#8ec5ff; margin-bottom:0.4rem; }
.reelopen__body h2 { font-size:clamp(1.5rem,3.4vw,2.6rem); letter-spacing:-0.02em; margin-bottom:0.9rem; }
.reelopen__go { color:var(--white); font-weight:700; text-decoration:none; border-bottom:2px solid var(--blue); }
.reelopen__close {
  position:absolute; top:1rem; right:1rem; width:2.4rem; height:2.4rem; border:0; cursor:pointer;
  border-radius:50%; background:rgba(255,255,255,0.9); color:var(--black); font-size:1rem;
}
.reelopen__close:hover { background:var(--blue); color:var(--white); }

@media (prefers-reduced-motion:reduce) {
  .reel__track { animation:none; }
  .reelopen__panel { animation:none; }
}
@media (max-width:640px) {
  .rcard { width:7rem; }
  .reelopen__panel { aspect-ratio:4/5; }
}

/* ---- the network core at the middle of "How It Works" ---- */
/* Section 4's title lives above the ring now — see index.ejs. Keeping it
   inside meant the back cards swung straight through it. */
.howhead { text-align:center; margin-bottom:0.4rem; }
.howhead .slide__title { margin-bottom:0.3rem; }
.netball {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:min(19rem,42vw); aspect-ratio:1; z-index:2; pointer-events:none;
}
.netball__svg { width:100%; height:100%; display:block; overflow:visible; }
.netball__halo { animation:nb-breathe 4.5s ease-in-out infinite; transform-origin:center; }
@keyframes nb-breathe { 0%,100% { opacity:0.55; transform:scale(0.94); } 50% { opacity:1; transform:scale(1.06); } }
.netball__nodes circle { fill:var(--white); }
.netball__links line { stroke:var(--white); stroke-width:0.8; }

/* the bolt out to a chapter */
.netball__zaps {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:var(--zw,100%); height:var(--zh,100%); overflow:visible; pointer-events:none;
}
.netball__bolt {
  fill:none; stroke:var(--white); stroke-width:2; stroke-linecap:round; stroke-linejoin:round;
  filter:drop-shadow(0 0 6px var(--white)) drop-shadow(0 0 14px #8ec5ff);
  animation:nb-bolt 0.4s ease-out forwards;
}
@keyframes nb-bolt {
  0%   { opacity:0; stroke-width:3.5; }
  15%  { opacity:1; }
  60%  { opacity:0.85; stroke-width:1.6; }
  100% { opacity:0; stroke-width:1; }
}
/* the card lights up when it is struck */
.orbit__node--card.is-zapped .ocard {
  box-shadow:0 0 0 2px var(--white), 0 0 34px 8px color-mix(in srgb, var(--white) 70%, transparent);
  animation:nb-hit 0.62s ease-out;
}
@keyframes nb-hit {
  0%   { filter:brightness(2.1); }
  100% { filter:brightness(1); }
}
@media (prefers-reduced-motion:reduce) { .netball__halo { animation:none; } }

/* ================= MOBILE =================
   Touch has no cursor, so the hover tricks go — but the picture stays the
   same: the ball at the centre, cards drifting past, tap one to open it.
   Only the sizes change. */
@media (hover:none), (max-width:640px) {

  /* section 1 — solid headline above a swipeable strip */
  .slide--hero { justify-content:flex-start; }
  /* Full bleed. On a desktop the reel is absolutely positioned across the whole
     slide, so it already runs off both edges. Going static on a phone put it
     back inside the slide's side padding — the strip started an inch in from
     the left and the first card was permanently half-hidden behind the gutter.
     100vw plus a negative margin of exactly that padding (50% of the content
     box minus 50vw) pushes it back out to the glass on both sides, and the
     reel's own overflow:hidden does the clipping. */
  .reel { position:static; transform:none; padding:0; margin-top:1rem;
          width:100vw; margin-inline:calc(50% - 50vw);
          -webkit-mask-image:none; mask-image:none; }
  .reel__track { animation-duration:34s; gap:0.7rem; }
  .rcard { width:7.6rem; }
  .herotitle { position:static; order:-1; margin-top:calc(var(--nav-h) + 1.2rem);
               font-size:clamp(1.5rem,6.6vw,2rem); }
  /* no cursor, no torch — a stuck hole would just look like a broken title */
  .herotitle.is-lit, .overtitle.is-lit, .slide__title.is-lit,
  .grain__heading.is-lit, .pack__title.is-lit, .prow__title.is-lit,
  .blk__h.is-lit {
    -webkit-mask-image:none !important; mask-image:none !important;
  }
  .herowatch { position:static; margin:1rem auto 0; }

  /* the rings keep turning, just smaller */
  .orbit--sov  { --orbit-rx:118; --orbit-ry:44; --orbit-min-scale:0.42; height:19rem; }
  .orbit--how  { --orbit-rx:126; --orbit-ry:48; --orbit-min-scale:0.38; height:20rem; }
  .orbit--sdg  { --orbit-rx:120; --orbit-ry:44; --orbit-min-scale:0.42; height:19rem; }
  .orbit--wide { --orbit-rx:120; --orbit-ry:44; --orbit-min-scale:0.42; height:19rem; }
  .orbit--pack { --orbit-rx:112; --orbit-ry:38; --orbit-min-scale:0.34; height:16rem; }
  .orbit__node--card, .orbit--sov .orbit__node--card { width:8.4rem; }
  .orbit__node--pack { width:5.2rem; }
  .ocard__body { padding:0.55rem 0.6rem 0.7rem; }
  .ocard__body strong { font-size:0.8rem; }
  .ocard__body em { font-size:0.68rem; line-height:1.35; }
  .netball { width:min(11rem,42vw); }
  .netball--map { width:min(13rem,50vw); }

  /* the ball must not sit on top of the cards on a small screen */
  .netball--sect { opacity:0.75; }

  .prow__nav { display:none; }
  .galcard__body { padding:1.4rem 1.4rem 1.6rem; }
  .certdisc__close { right:26%; top:62%; }
}

/* ================= shared: centred see-through titles =================
   Every section title takes the same treatment as section 1 — the title sits
   over the moving cards and goes see-through around the cursor. One rule, so
   a new section gets it without anyone remembering to ask. */
.herotitle.is-lit, .overtitle.is-lit, .slide__title.is-lit,
.grain__heading.is-lit, .pack__title.is-lit, .prow__title.is-lit,
.blk__h.is-lit {
  -webkit-mask-image:radial-gradient(circle var(--tr,110px) at var(--tx,50%) var(--ty,50%),
    transparent 0, transparent 55%, #000 100%);
          mask-image:radial-gradient(circle var(--tr,110px) at var(--tx,50%) var(--ty,50%),
    transparent 0, transparent 55%, #000 100%);
}
.slide__title, .grain__heading, .pack__title, .prow__title, .blk__h { cursor:default; }

.overtitle {
  position:relative; z-index:4; text-align:center; text-transform:uppercase;
  letter-spacing:-0.01em; max-width:min(42rem,90vw); margin:0 auto;
  text-shadow:0 4px 30px rgba(0,0,0,0.55); cursor:default;
}
.overtitle--dark { color:var(--black); text-shadow:0 2px 24px rgba(255,255,255,0.85); }
.overtitle.is-lit {
  -webkit-mask-image:radial-gradient(circle var(--tr,110px) at var(--tx,50%) var(--ty,50%),
    transparent 0, transparent 55%, #000 100%);
          mask-image:radial-gradient(circle var(--tr,110px) at var(--tx,50%) var(--ty,50%),
    transparent 0, transparent 55%, #000 100%);
}
.overtitle__sub {
  position:relative; z-index:4; text-align:center; margin:0.7rem auto 0;
  max-width:38rem; font-size:clamp(0.92rem,1.6vw,1.1rem); opacity:0.78;
}
.overtitle__sub--dark { color:var(--black); opacity:0.7; }

/* section 3 and 4 cards now match section 1's size */
.orbit__node--card,
.orbit--sov .orbit__node--card { width:clamp(8rem,13vw,11.5rem); }
.ocard { border:0; padding:0; cursor:pointer; text-align:left; width:100%; }

/* a card opened from a ring */
.ocard.is-open, .rcard.is-open, .lcard.is-open { outline:2px solid var(--white); outline-offset:3px; }

/* ---- Trust: the P&G-style logo drift ---- */
.reel--pale { --reel-mask:transparent; }
.reel__track--slow { animation-duration:70s; }
.lcard {
  flex:none; width:clamp(8rem,12vw,10.5rem); border:0; background:none; cursor:pointer;
  display:flex; flex-direction:column; align-items:center; gap:0.7rem; padding:0.4rem;
}
.lcard__disc {
  width:clamp(6.5rem,9vw,8.4rem); aspect-ratio:1; border-radius:50%;
  background:var(--white); display:grid; place-items:center; padding:1.1rem;
  box-shadow:0 16px 36px -20px rgba(10,2,3,0.4);
  transition:transform 0.28s ease, box-shadow 0.28s ease;
}
.lcard__disc img { max-width:100%; max-height:100%; object-fit:contain; display:block; }
.lcard:hover .lcard__disc {
  transform:translateY(-6px) scale(1.05);
  box-shadow:0 22px 46px -18px color-mix(in srgb, var(--blue) 70%, transparent);
}
.lcard__name { font-size:0.78rem; font-weight:700; color:var(--black); opacity:0.72; text-align:center; }
#commitment .thanks { position:relative; z-index:4; text-align:center; margin-top:1.2rem; }

/* ---- Impact: the SDG goals ---- */
.rcard--sdg {
  aspect-ratio:1; background:var(--white); padding:0.9rem;
  display:grid; place-items:center;
}
.rcard--sdg img { width:100%; height:100%; object-fit:contain; }
.rcard--sdg .rcard__tag { background:none; padding:0.4rem; color:var(--black); opacity:0.55; }

/* both new sections stack their reel behind a centred title */
#commitment, #sdg { position:relative; justify-content:center; }
#commitment .reel, #sdg .reel { position:absolute; left:0; right:0; top:50%; transform:translateY(-50%); }

/* ================= footer, Dr. KC's slide 10 =================
   A blue block with a curved top edge and a "Back to top" pill riding it. */
.pgfoot {
  position:relative; background:var(--blue); color:var(--white);
  padding:5.5rem clamp(1.4rem,5vw,4.5rem) 1.6rem; margin-top:4rem;
}
.pgfoot__curve {
  position:absolute; left:0; right:0; top:-3.4rem; height:5rem;
  background:var(--blue); border-radius:50% 50% 0 0 / 100% 100% 0 0;
}
.pgfoot__top {
  position:absolute; top:1.4rem; left:50%; transform:translateX(-50%);
  border:1.5px solid rgba(255,255,255,0.85); border-radius:999px;
  padding:0.55rem 1.5rem; color:var(--white); text-decoration:none;
  font-weight:700; font-size:0.9rem; transition:background 0.2s ease, color 0.2s ease;
}
.pgfoot__top:hover { background:var(--white); color:var(--blue); }

.pgfoot__grid {
  display:grid; gap:2rem clamp(1.4rem,3vw,3rem); max-width:78rem; margin:0 auto;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
}
.pgfoot__contact { display:flex; flex-direction:column; gap:0.5rem; }
.pgfoot__col h3 {
  font-size:0.78rem; font-weight:700; letter-spacing:0.1em; text-transform:uppercase;
  margin-bottom:0.9rem;
}
.pgfoot__col a, .pgfoot__contact a {
  display:block; color:var(--white); text-decoration:none; opacity:0.86;
  font-size:0.86rem; margin-bottom:0.5rem; transition:opacity 0.2s ease;
}
.pgfoot__col a:hover, .pgfoot__contact a:hover { opacity:1; text-decoration:underline; }
.pgfoot__col a em, .pgfoot__contact a em { font-style:normal; font-size:0.72rem; opacity:0.75; }

.pgfoot__base {
  display:flex; align-items:center; justify-content:space-between; gap:1rem; flex-wrap:wrap;
  max-width:78rem; margin:2.6rem auto 0; padding-top:1.4rem;
  border-top:1px solid rgba(255,255,255,0.22);
}
.pgfoot__locale {
  border:1.5px solid rgba(255,255,255,0.75); border-radius:999px;
  padding:0.4rem 1.1rem; font-size:0.82rem; font-weight:700;
}
.pgfoot__copy { font-size:0.8rem; opacity:0.78; }
.pgfoot__social { display:flex; gap:1rem; }
.pgfoot__social a { color:var(--white); opacity:0.85; transition:opacity 0.2s ease, transform 0.2s ease; }
.pgfoot__social a:hover { opacity:1; transform:translateY(-2px); }
.pgfoot__social svg { width:1.3rem; height:1.3rem; display:block; }
@media (max-width:640px) {
  .pgfoot__base { justify-content:center; text-align:center; }
  .pgfoot__copy { order:3; width:100%; }
}

/* commitment: partner marks as rounded squares, section-1 size, under the thanks */
#commitment { justify-content:center; }
#commitment .reel { position:static; transform:none; margin-top:var(--blk-rest,2.6rem); overflow:hidden; }
.lcard {
  flex:none; width:clamp(8rem,13vw,11.5rem); aspect-ratio:3/4;
  border:0; cursor:pointer; border-radius:18px; overflow:hidden;
  background:var(--white); padding:1.2rem 1rem;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:0.9rem;
  box-shadow:0 18px 40px -24px rgba(10,2,3,0.4);
  transition:transform 0.28s ease, box-shadow 0.28s ease;
}
.lcard img { max-width:100%; max-height:52%; object-fit:contain; display:block; }
.lcard:hover { transform:translateY(-6px); box-shadow:0 24px 50px -20px color-mix(in srgb, var(--blue) 65%, transparent); }
.lcard__name { font-size:0.78rem; font-weight:700; color:var(--black); opacity:0.72; text-align:center; line-height:1.35; }

/* impact: the SDG ring, with the earth at its core */
.orbit--sdg { --orbit-rx:420; --orbit-ry:104; --orbit-min-scale:0.52; height:clamp(27rem,56vh,36rem); }
.ocard--sdg { background:var(--white); }
.ocard--sdg .ocard__media { aspect-ratio:1; padding:0.9rem; background:var(--white); display:grid; place-items:center; }
.ocard--sdg .ocard__media img { width:100%; height:100%; object-fit:contain; }
.netball--earth .netball__nodes circle { fill:#bdf7d8; }
.netball--earth .netball__links line { stroke:#7fe3c0; }
.netball__globe {
  fill:none; stroke:#4fd1a5; stroke-width:1.1; opacity:0.5;
  animation:nb-breathe 5.5s ease-in-out infinite;
}
/* the bolt takes the earth's colours in this section */
.netball--earth .netball__bolt {
  stroke:#8ef0c4;
  filter:drop-shadow(0 0 6px #8ef0c4) drop-shadow(0 0 14px #35a8e0);
}
.orbit--sdg .orbit__node--card.is-zapped .ocard {
  box-shadow:0 0 0 2px #8ef0c4, 0 0 34px 8px color-mix(in srgb, #35a8e0 70%, transparent);
}
@media (max-height:860px) { .orbit--sdg { --orbit-ry:80; --orbit-rx:360; height:23rem; } }

/* ================= the studio treatment =================
   Every section from 2 onwards is staged like a room: a light from above, a
   shadow on the floor, and information flowing between the floors. */
.studio { position:relative; isolation:isolate; }
.studio__rig { position:absolute; inset:0; pointer-events:none; z-index:1; overflow:hidden; }

/* ---- the room ----
   A studio: a lit strip across the ceiling, light slots down the side walls,
   a floor that catches the reflection. Dark rooms and white rooms use the
   same geometry so every section reads as the same space. */
.studio__ceil {
  position:absolute; left:8%; right:8%; top:0; height:4px; border-radius:0 0 4px 4px;
  background:linear-gradient(90deg, transparent, var(--white) 12%, var(--white) 88%, transparent);
  box-shadow:0 0 22px 5px color-mix(in srgb, var(--white) 60%, transparent),
             0 0 60px 18px color-mix(in srgb, var(--white) 26%, transparent);
  opacity:0.85;
}
.studio__strip {
  position:absolute; top:12%; width:3px; height:46%; border-radius:3px;
  background:linear-gradient(var(--white), color-mix(in srgb, var(--white) 30%, transparent));
  box-shadow:0 0 16px 3px color-mix(in srgb, var(--white) 45%, transparent);
  opacity:0.5;
}
.studio__strip--l { left:3.5%; transform:skewY(9deg); }
.studio__strip--r { right:3.5%; transform:skewY(-9deg); }

/* the light the ceiling strip throws into the room */
.studio__light {
  position:absolute; left:50%; top:0; transform:translateX(-50%);
  width:min(120rem,150%); height:82%;
  background:radial-gradient(ellipse 46% 100% at 50% 0%,
    color-mix(in srgb, var(--white) 20%, transparent) 0%,
    color-mix(in srgb, var(--white) 6%, transparent) 45%, transparent 74%);
}
/* the back wall meeting the floor, and the sheen on the floor itself */
.studio__floor {
  position:absolute; left:0; right:0; bottom:0; height:34%;
  background:linear-gradient(transparent, color-mix(in srgb, var(--black) 46%, transparent));
}
.studio__gloss {
  position:absolute; left:12%; right:12%; bottom:0; height:26%;
  background:radial-gradient(ellipse 60% 100% at 50% 100%,
    color-mix(in srgb, var(--white) 13%, transparent), transparent 70%);
  filter:blur(6px);
}

/* white rooms: the same space, lit rather than dark */
.slide--light .studio__ceil, .pack .studio__ceil {
  background:linear-gradient(90deg, transparent, var(--white) 12%, var(--white) 88%, transparent);
  box-shadow:0 0 22px 6px color-mix(in srgb, var(--blue) 22%, transparent),
             0 2px 30px 10px color-mix(in srgb, var(--black) 10%, transparent);
}
.slide--light .studio__strip, .pack .studio__strip {
  background:linear-gradient(var(--white), color-mix(in srgb, var(--white) 40%, transparent));
  box-shadow:0 0 18px 5px color-mix(in srgb, var(--black) 12%, transparent);
  opacity:0.9;
}
.slide--light .studio__light, .pack .studio__light {
  background:radial-gradient(ellipse 46% 100% at 50% 0%,
    color-mix(in srgb, var(--black) 6%, transparent) 0%, transparent 72%);
}
.slide--light .studio__floor, .pack .studio__floor {
  background:linear-gradient(transparent, color-mix(in srgb, var(--black) 12%, transparent));
}
.slide--light .studio__gloss, .pack .studio__gloss {
  background:radial-gradient(ellipse 60% 100% at 50% 100%,
    color-mix(in srgb, var(--white) 85%, transparent), transparent 70%);
}
/* the blue room keeps its colour, just gets the same lighting */
.slide--blue .studio__floor { background:linear-gradient(transparent, color-mix(in srgb, #003c8f 45%, transparent)); }

/* the section's own content must sit above the rig */
.studio > *:not(.studio__rig):not(.netball) { position:relative; z-index:2; }

/* ================= NEUON Starter Pack, in the light ================= */
.pack { background:var(--white); color:var(--black); }
.pack .kicker { color:var(--blue); }
.pack__h em { color:var(--blue); }
.pack__lead { opacity:0.66; }
.pack__pickhint { opacity:0.5; }
.pack__swap, .pack__again {
  border-color:color-mix(in srgb, var(--black) 22%, transparent); color:var(--black);
}
.pack__swap:hover, .pack__again:hover { background:var(--blue); border-color:var(--blue); color:var(--white); }
.pack .netball__nodes circle { fill:var(--blue); }
.pack .netball__links line { stroke:var(--blue); }
.pack .netball__bolt {
  stroke:var(--blue);
  filter:drop-shadow(0 0 5px var(--blue)) drop-shadow(0 0 14px color-mix(in srgb, var(--blue) 70%, transparent));
}
.orbit__node--pack.is-zapped .ppack__foil {
  box-shadow:0 0 0 2px var(--white), 0 0 34px 10px color-mix(in srgb, var(--blue) 75%, transparent);
  animation:nb-hit 0.62s ease-out;
}

/* ================= the dome's arc wording ================= */
.certarc { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; }
.certarc__t {
  fill:var(--blue); font-family:'Inter',sans-serif; font-weight:700;
  font-size:21px; letter-spacing:6px; opacity:0.8;
}
.certdisc__kicker--sr {
  position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%);
}
.clogo-wrap { border:0; background:none; padding:0; cursor:pointer; }

/* ================= cards fly toward the viewer =================
   The panel arrives like a card thrown at the screen: angled away, spinning
   flat, growing as it comes. */
.reelopen { perspective:1400px; }
.reelopen__panel { animation:card-throw 0.62s cubic-bezier(0.16,0.84,0.28,1.06); }
@keyframes card-throw {
  0%   { opacity:0; transform:translate3d(28vw,14vh,-900px) rotateY(38deg) rotateZ(9deg) scale(0.42); }
  55%  { opacity:1; }
  100% { opacity:1; transform:none; }
}
@media (prefers-reduced-motion:reduce) {
  .reelopen__panel { animation:none; }
  .studio__rig { display:none; }
}


/* the dome's own core — same engine as every section */
.netball--dome { width:9rem; position:absolute; left:50%; top:46%; transform:translate(-50%,-50%); z-index:0; }
.netball--dome .netball__nodes circle { fill:var(--blue); }
.netball--dome .netball__links line { stroke:var(--blue); }
.netball--dome .netball__bolt {
  stroke:var(--blue); stroke-width:1.6;
  filter:drop-shadow(0 0 4px var(--blue)) drop-shadow(0 0 12px color-mix(in srgb, var(--blue) 60%, transparent));
}
.orbit--cert .orbit__node.is-zapped .clogo {
  box-shadow:0 0 0 2px var(--blue), 0 0 26px 6px color-mix(in srgb, var(--blue) 55%, transparent);
  animation:nb-hit 0.62s ease-out;
}
.orbit--cert { position:relative; z-index:1; }

/* ---- one core per section, at its centre ---- */
.netball--sect {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:min(15rem,32vw); aspect-ratio:1; z-index:1; pointer-events:none;
}
.netball--sect .netball__halo { fill:none; }
.netball--sect .netball__nodes circle { fill:var(--white); opacity:0.5; }
.netball--sect .netball__links line { stroke:var(--white); }
.slide--light .netball--sect .netball__nodes circle,
.slide--light .netball--sect .netball__links line { fill:var(--blue); stroke:var(--blue); }
.netball--sect .netball__bolt { stroke-width:1.5; }
.slide--light .netball--sect .netball__bolt {
  stroke:var(--blue);
  filter:drop-shadow(0 0 4px var(--blue)) drop-shadow(0 0 12px color-mix(in srgb, var(--blue) 55%, transparent));
}
/* anything struck lights briefly, whatever kind of card it is */
.is-zapped { position:relative; }
.news-card.is-zapped, .allies__card.is-zapped, .feed__card.is-zapped, .lcard.is-zapped {
  box-shadow:0 0 0 2px color-mix(in srgb, var(--blue) 80%, var(--white)),
             0 0 30px 8px color-mix(in srgb, var(--blue) 55%, transparent);
  animation:nb-hit 0.62s ease-out;
}

/* every section from 2 on reads the same way: centred title above its content */
#news, #allies, #growth { text-align:center; }
#news > .slide__title, #allies > .slide__title, #growth > .slide__title,
#news > .lede, #allies > .lede, #growth > .lede { margin-left:auto; margin-right:auto; }
#news .news-grid, #growth .phase-row { text-align:left; }
.sovhead { position:relative; z-index:3; }

/* sovereign's core is the Sarawak map itself — the ball stays out of sight,
   only its bolts fire */
.netball--quiet .netball__svg { opacity:0; }
.netball--quiet { width:min(26rem,50vw); }

/* ================= the shared wide ring =================
   Trust, NEUStory, NEUFamily and Growth all use the same shape as How It
   Works: items circling a core. Adding a second batch later just means a
   second ring — the geometry already supports it. */
.orbit--wide { --orbit-rx:400; --orbit-ry:104; --orbit-min-scale:0.5; height:clamp(24rem,50vh,32rem); }
@media (max-height:860px) { .orbit--wide { --orbit-ry:78; --orbit-rx:340; height:21rem; } }

/* a card with no picture — the text carries it */
.ocard--plain { background:var(--white); color:var(--black); padding:1.2rem 1.1rem; }
.ocard--plain .ocard__body { padding:0; }
.slide--dark .ocard--plain, .slide--blue .ocard--plain { background:color-mix(in srgb, var(--white) 96%, var(--blue)); }
.ocard__period {
  display:block; font-size:0.68rem; font-weight:700; letter-spacing:0.1em;
  text-transform:uppercase; color:var(--blue); margin-bottom:0.35rem;
}
.ocard__letter {
  display:grid; place-items:center; width:2.4rem; height:2.4rem; margin-bottom:0.6rem;
  border-radius:50%; background:var(--blue); color:var(--white);
  font-weight:700; font-size:1.1rem;
}

/* ================= credential logos as small balls =================
   Small enough that nothing collides with the arc wording or the play button;
   click one to see the whole logo in the panel. */
.clogo {
  width:3.4rem; height:3.4rem; border-radius:50%; padding:0.5rem;
  background:var(--white); display:grid; place-items:center;
  box-shadow:0 6px 18px -8px rgba(10,2,3,0.35);
  transition:transform 0.25s ease, box-shadow 0.25s ease;
}
.clogo img { max-width:100%; max-height:100%; object-fit:contain; display:block; }
/* THE CERTIFICATES, AS BIG AS THE DOME ALLOWS
   These are the whole point of the panel — MD status, MySTI, SIRIM, the
   ministries — and they were being shown at a size where nobody past the front
   row could tell one from another. Each now sits in a disc slightly LARGER
   than the blue NEUON disc on the bar, with the ring pushed out to match so
   they still clear each other. */
.orbit--cert .clogo {
  width:calc(var(--nav-disc) * 1.06); height:calc(var(--nav-disc) * 1.06);
  padding:0.35rem;
}
.orbit--cert .orbit__node { width:calc(var(--nav-disc) * 1.06 + 0.8rem); }
/* Bigger discs need a wider ring or the front three sit on top of each other,
   and a deeper falloff so the ones round the back clearly read as behind
   rather than as a second row of half-size logos. */
.orbit--cert {
  height:calc(var(--nav-disc) * 1.55);
  --orbit-rx:300; --orbit-ry:46; --orbit-min-scale:0.40;
}
.orbit--cert .clogo-wrap:hover .clogo {
  transform:translateY(-3px) scale(1.12);
  box-shadow:0 10px 24px -8px color-mix(in srgb, var(--blue) 70%, transparent);
}
.orbit--cert .clogo__name { display:none; }
/* the Trust ring shows them larger, with their names */
.clogo--lg { width:6.4rem; height:6.4rem; padding:1rem; }
.orbit--wide .orbit__node--logo { width:8rem; }
.orbit--wide .clogo-wrap { display:flex; flex-direction:column; align-items:center; gap:0.5rem; }
.orbit--wide .clogo__name { opacity:0; transition:opacity 0.25s ease; font-size:0.7rem; }
.orbit--wide .orbit__node.is-front .clogo__name { opacity:1; }

/* the panel shows a logo whole, not cropped */
.reelopen__panel img[src$=".png"], .reelopen__panel img[src$=".svg"] {
  object-fit:contain; background:var(--white); padding:clamp(2rem,6vw,4rem);
}

/* NEUFamily carries a hero row and the G.R.A.I.N. ring; on a laptop the two
   together overrun the slide, so the row gives up its height first */
#family .family__row { align-items:center; }
@media (max-height:900px) {
  #family .family__row { display:block; }
  #family .family__row img, #family .family__row .family__photo { display:none; }
  #family .slide__title { font-size:clamp(1.4rem,3vw,1.9rem); margin-bottom:0.4rem; }
  #family .lede { font-size:0.95rem; margin-bottom:0.7rem; }
  #family .family__ctas { margin-bottom:0.4rem; }
  #family .grain__heading { margin:0.2rem 0; font-size:0.9rem; }
}

/* ---- every core is the same ball; Sovereign's simply has the map inside ---- */
.netball--map { width:min(22rem,44vw); }
.netball__map {
  position:absolute; inset:12%; display:grid; place-items:center;
  opacity:0.5; pointer-events:none;
}
.netball__map svg { width:100%; height:100%; }
.netball--map .netball__svg { position:relative; z-index:2; }
/* the SDG core drops its green — it is the same blue ball as the rest */
.netball--sect .netball__globe { display:none; }

/* ---- logos always inside their circle ---- */
.clogo, .clogo--lg { overflow:hidden; }
.clogo img, .clogo--lg img {
  max-width:100%; max-height:100%; width:auto; height:auto; object-fit:contain;
}

/* ---- NEUFamily and Partners centred, like every other section ---- */
#family, #allies { text-align:center; }
#family .family__row {
  display:flex; flex-direction:column; align-items:center; gap:0.6rem;
}
#family .family__row > div { max-width:46rem; margin:0 auto; }
#family .family__ctas { justify-content:center; }
#family .lede, #allies .lede { margin-left:auto; margin-right:auto; }
#allies .allies__card { margin-left:auto; margin-right:auto; max-width:26rem; }
#family .grain__heading { text-align:center; }

/* A tall logo (SFC is 2:3) was still overflowing its ball: max-height:100% on
   an auto-height grid item does not always bind. Filling the box and letting
   object-fit do the letterboxing always does. */
.clogo img, .clogo--lg img {
  width:100%; height:100%; object-fit:contain; display:block;
  max-width:100%; max-height:100%;
}

/* Percentage heights on a grid item resolve against an auto-sized row, so
   `height:100%` fell back to the image's intrinsic ratio and tall logos broke
   out. Pinning the image to the circle's inset makes the box definite. */
.clogo { position:relative; padding:0; }
/* The artwork fills its disc. At inset 22% a wide logo like Malaysia Digital
   was rendering at about a third of the circle it was sitting in — most of
   what you saw was white space. */
.clogo img, .clogo--lg img {
  position:absolute; inset:12%;
  width:auto; height:auto; max-width:none; max-height:none;
  object-fit:contain;
}
.clogo--lg img { inset:10%; }

/* ---- 4 · the top bar reads louder ---- */
.nav__pill a:not(.nav__brand) { font-size:1.02rem; font-weight:800; opacity:0.82; letter-spacing:-0.01em; }
.nav__pill a:not(.nav__brand):hover, .nav__pill a.active { opacity:1; }
.nav__pill a.active { text-decoration:underline; text-underline-offset:6px; text-decoration-thickness:3px; }

/* ---- 6 · the logo reads as a button by weight, not by pulsing ---- */
.nav__radar { display:none; }
.nav__disc {
  box-shadow:0 6px 0 -1px color-mix(in srgb, var(--blue) 55%, var(--black)),
             0 12px 26px -6px color-mix(in srgb, var(--blue) 70%, transparent),
             inset 0 2px 0 color-mix(in srgb, var(--white) 45%, transparent);
}
.nav__brand--btn:hover .nav__disc {
  transform:translateX(-50%) translateY(-2px) scale(1.04);
  box-shadow:0 8px 0 -1px color-mix(in srgb, var(--blue) 55%, var(--black)),
             0 16px 32px -6px color-mix(in srgb, var(--blue) 80%, transparent),
             inset 0 2px 0 color-mix(in srgb, var(--white) 45%, transparent);
}
.nav__brand--btn:active .nav__disc {
  transform:translateX(-50%) translateY(3px) scale(0.99);
  box-shadow:0 2px 0 -1px color-mix(in srgb, var(--blue) 55%, var(--black)),
             0 6px 16px -6px color-mix(in srgb, var(--blue) 70%, transparent);
}

/* ---- 3 · the core charges before it fires ---- */
.netball.is-charging .netball__nodes circle { animation:nb-charge 0.62s ease-in-out; }
.netball.is-charging .netball__links line { animation:nb-charge-line 0.62s ease-in-out; }
@keyframes nb-charge { 0%,100% { opacity:0.5; } 55% { opacity:1; } }
@keyframes nb-charge-line { 0%,100% { opacity:0.2; } 55% { opacity:0.95; } }
.netball.is-charging .netball__halo { animation:nb-charge-halo 0.62s ease-out; }
@keyframes nb-charge-halo { 0% { transform:scale(0.9); } 60% { transform:scale(1.25); } 100% { transform:scale(1); } }

/* ---- 5 · film cards ---- */
.rcard--film { aspect-ratio:16/9; width:clamp(11rem,19vw,16rem); }
.rcard--film .rcard__tag { font-size:0.7rem; line-height:1.3; padding:2rem 0.7rem 0.6rem; }

.reelopen__video { position:absolute; inset:0; background:var(--black); }
.reelopen__video[hidden] { display:none; }
.reelopen__video iframe { width:100%; height:100%; border:0; display:block; }
.reelopen__panel:has(.reelopen__video:not([hidden])) .reelopen__body {
  position:static; background:none; padding:0.9rem clamp(1rem,3vw,1.8rem) 1.1rem;
}
.reelopen__panel:has(.reelopen__video:not([hidden])) { aspect-ratio:auto; }

/* ---- 7 · NEUFamily drops the big round portrait ---- */
#family .family__photo, #family .family__row img, #family .family__round { display:none !important; }

/* ---- 2 · the credentials dome fills the screen on a phone ---- */
@media (hover:none), (max-width:640px) {
  .certdisc {
    width:100vw; height:100dvh; aspect-ratio:auto; border-radius:0;
    left:0; top:0; transform:none;
  }
  /* On a phone the dome is a full sheet, so the core and the ring stack and
     sit together in the middle of it. Left absolute, the core drifted to the
     bottom of an otherwise empty screen, nowhere near the logos it belongs to. */
  .certdisc { display:flex; flex-direction:column; align-items:center; justify-content:center; }
  .certdisc__in { position:static; width:86%; margin:0 auto; padding-top:0; transform:none; }
  .certarc { display:none; }
  .certdisc__close { position:absolute; top:calc(var(--nav-h) + 0.6rem); right:1rem; }
  .netball--dome { position:static; width:8rem; margin:0 auto 1rem; transform:none; }
  .orbit--cert { --orbit-rx:110; --orbit-ry:26; height:6rem; }
  .certwave { display:none; }
}

/* ================= 2 · We Teach, It Learn =================
   NO TOP PADDING ON THE SECTION. It used to hold the content clear of the
   nav disc, and the pinned stage inside now does that with padding of its
   own — so all this was still doing was holding the film and the scrim 160px
   down from the top of the section. Above that strip was flat section colour;
   below it, film under a 94% scrim, which is a few per cent lighter. That
   difference is the horizontal line across the top of the section. */
.slide--teach { padding-top:0; }
.teach3 {
  position:relative; z-index:2; display:grid; align-items:center;
  grid-template-columns:1fr 1.1fr 1fr; gap:clamp(1rem,3vw,3rem);
  width:min(78rem,94vw); margin:0 auto;
}
.teach3__step {
  display:flex; align-items:center; gap:0.6rem; margin-bottom:1rem;
  font-size:0.76rem; font-weight:700; letter-spacing:0.14em; text-transform:uppercase; color:#8ec5ff;
}
.teach3__step span {
  display:grid; place-items:center; width:1.6rem; height:1.6rem; border-radius:50%;
  background:var(--blue); color:var(--white); font-size:0.78rem;
}
.teach3__feeds, .teach3__results { list-style:none; display:grid; gap:0.5rem; }
.teach3__feeds li {
  display:flex; align-items:center; gap:0.7rem; padding:0.55rem 0.85rem;
  border:1px solid rgba(255,255,255,0.16); border-radius:12px;
  background:rgba(255,255,255,0.05); font-size:0.85rem;
  animation:feed-send 3.6s ease-in-out infinite; animation-delay:var(--d,0s);
}
@keyframes feed-send {
  0%,70%,100% { transform:translateX(0); border-color:rgba(255,255,255,0.16); }
  20%         { transform:translateX(14px); border-color:#8ec5ff; }
}
.teach3__glyph { color:#8ec5ff; font-size:1rem; }

.teach3__brain { position:relative; display:grid; place-items:center; aspect-ratio:1; }
.teach3__brain svg { width:100%; height:100%; }
.teach3__mesh circle { fill:var(--white); }
.teach3__mesh line { stroke:#8ec5ff; stroke-width:0.7; }
.teach3__pulse {
  position:absolute; inset:14%; border-radius:50%; border:2px solid #8ec5ff;
  opacity:0; animation:teach-ping 3s ease-out infinite;
}
.teach3__pulse--2 { animation-delay:1.5s; }
@keyframes teach-ping { 0% { transform:scale(0.7); opacity:0.7; } 100% { transform:scale(1.5); opacity:0; } }
.teach3__chip {
  position:absolute; padding:0.4rem 0.9rem; border-radius:8px;
  background:var(--blue); color:var(--white); font-weight:700;
  font-size:0.7rem; letter-spacing:0.14em;
  box-shadow:0 0 24px 4px color-mix(in srgb, var(--blue) 70%, transparent);
}
.teach3__note { text-align:center; font-size:0.78rem; opacity:0.6; margin-top:0.8rem; }

.teach3__res {
  padding:0.7rem 0.9rem; border-radius:12px; font-size:0.85rem;
  border:1px solid rgba(255,255,255,0.16); background:rgba(255,255,255,0.05);
  animation:res-land 3.6s ease-in-out infinite; animation-delay:var(--d,0s);
}
.teach3__res strong { display:block; color:#8ec5ff; font-size:0.72rem; letter-spacing:0.1em; text-transform:uppercase; }
.teach3__res em { font-style:normal; opacity:0.85; }
@keyframes res-land {
  0%,40%   { opacity:0.25; transform:translateX(-10px); }
  60%,100% { opacity:1;    transform:translateX(0); }
}
/* the honest one: it gets corrected, then it lands */
.teach3__res--fix { border-color:#ffb84d55; }
.teach3__fix {
  display:block; margin-top:0.3rem; font-size:0.7rem; font-weight:700; color:#ffcf87;
  animation:res-fix 3.6s ease-in-out infinite;
}
@keyframes res-fix { 0%,55% { opacity:1; } 70%,100% { opacity:0.35; } }

/* ================= 1 · the reel fills the room =================
   The card WIDTH is not set here. Four rules further down claim it and the
   winner is `.reel--desk .rcard--film`, which is both more specific and
   !important — changing this one moves nothing, which cost me a round trip. */
.reel { padding:1.5rem 0; }


/* ================= 8 · the film plays big ================= */
.reelopen__panel:has(.reelopen__video:not([hidden])) {
  width:min(92rem,96vw); aspect-ratio:16/9; height:auto; max-height:88vh;
}
.reelopen__panel:has(.reelopen__video:not([hidden])) .reelopen__body {
  position:absolute; inset:auto 0 0 0;
  background:linear-gradient(transparent, rgba(10,2,3,0.9));
  padding:2.4rem clamp(1rem,3vw,2rem) 1rem; pointer-events:none;
}
.reelopen__panel:has(.reelopen__video:not([hidden])) .reelopen__body h2 { font-size:clamp(1rem,2vw,1.4rem); }
.reelopen__video { z-index:1; }
.reelopen__close { z-index:3; }

/* ================= 7 · picking a pack dims the room behind it ================= */
.pack.has-pick .pack__wrap, .pack.has-pick .pack__pickhint { filter:blur(2px); opacity:0.5; transition:0.3s ease; }
.pack.has-pick .studio__rig { filter:blur(3px); }

/* ================= 3 · moving between rooms ================= */
.studio { --enter:0; }
.studio.is-entering .studio__rig::after {
  content:''; position:absolute; inset:0;
  background:linear-gradient(105deg, transparent 35%,
    color-mix(in srgb, var(--white) 22%, transparent) 50%, transparent 65%);
  animation:room-sweep 0.9s ease-out forwards;
}
@keyframes room-sweep { from { transform:translateX(-100%); } to { transform:translateX(100%); } }
.studio.is-entering > *:not(.studio__rig) { animation:room-in 0.7s cubic-bezier(0.2,0.9,0.3,1) both; }
@keyframes room-in { from { opacity:0; transform:translateY(22px) scale(0.985); } }

/* ================= 4 · the room, with information floating in it ================= */
.studio__dust { position:absolute; inset:0; overflow:hidden; }
.studio__dust i {
  position:absolute; display:block; border-radius:50%;
  background:color-mix(in srgb, var(--white) 70%, transparent);
  animation:dust-rise linear infinite;
}
.slide--light .studio__dust i, .pack .studio__dust i { background:color-mix(in srgb, var(--blue) 40%, transparent); }
@keyframes dust-rise {
  from { transform:translateY(18vh) scale(0.6); opacity:0; }
  20%,80% { opacity:0.55; }
  to   { transform:translateY(-22vh) scale(1); opacity:0; }
}
@media (prefers-reduced-motion:reduce) {
  .studio__dust, .teach3__pulse { display:none; }
  .teach3__feeds li, .teach3__res, .teach3__fix { animation:none; }
  .studio.is-entering > *:not(.studio__rig) { animation:none; }
}

/* The film cards are sized from the section's height, not an arbitrary width,
   so the reel fills roughly two thirds of the room instead of floating in it. */
.rcard--film {
  width:auto; height:clamp(13rem,46vh,25rem); aspect-ratio:16/9;
}
.reel { padding:0; }
.rcard--film .rcard__tag { font-size:0.86rem; padding:2.6rem 1rem 0.9rem; }
@media (max-width:640px) { .rcard--film { height:clamp(9rem,26vh,13rem); } }

/* The film panel is flagged from JS rather than matched with :has(), which was
   not binding here and left the panel collapsed to the size of its buttons. */
.reelopen.is-film .reelopen__panel {
  width:min(92rem,96vw); height:auto; aspect-ratio:16/9; max-height:86vh;
}
.reelopen.is-film .reelopen__body {
  position:absolute; inset:auto 0 0 0; pointer-events:none;
  background:linear-gradient(transparent, rgba(10,2,3,0.9));
  padding:2.6rem clamp(1rem,3vw,2rem) 1rem;
}
.reelopen.is-film .reelopen__body h2 { font-size:clamp(1rem,2vw,1.5rem); margin-bottom:0.2rem; }
.reelopen.is-film .reelopen__go { display:none; }

/* the film cards: width driven by the room's height, so they scale together */
.rcard--film { width:clamp(19rem,72vh,42rem) !important; height:auto !important; aspect-ratio:16/9; }
@media (max-width:640px) { .rcard--film { width:clamp(13rem,44vh,20rem) !important; } }

/* ================= ONE GEOMETRY FOR EVERY RING =================
   The Starter Pack is the reference: same radius, same tilt, same card size,
   same distance from the core, same foil sheen. Every other ring matches it,
   so a presenter sees the identical picture in every room. */
:root {
  --ring-rx:340; --ring-ry:58; --ring-min:0.34; --ring-h:24rem;
  --ring-card:clamp(6.4rem,10vw,8.2rem);
}
.orbit--pack, .orbit--sov, .orbit--how, .orbit--sdg, .orbit--wide {
  --orbit-rx:var(--ring-rx); --orbit-ry:var(--ring-ry);
  --orbit-min-scale:var(--ring-min); height:var(--ring-h);
}
.orbit--sov .orbit__node--card, .orbit--how .orbit__node--card,
.orbit--sdg .orbit__node--card, .orbit--wide .orbit__node--card,
.orbit--wide .orbit__node--logo, .orbit__node--card { width:var(--ring-card); }

.ocard { position:relative; overflow:hidden; border-radius:14px; }
.ocard::before {
  content:''; position:absolute; inset:-40% -120%; pointer-events:none; z-index:3;
  background:linear-gradient(74deg, transparent 42%, rgba(255,255,255,0.45) 50%, transparent 58%);
  animation:pack-shine 4.5s ease-in-out infinite;
}
.ocard__media { aspect-ratio:1; }
.ocard__body { padding:0.6rem 0.65rem 0.75rem; }
.ocard__body strong { font-size:0.8rem; }
.ocard__body em { font-size:0.66rem; line-height:1.35; }
.clogo--lg { width:100%; aspect-ratio:1; height:auto; }

@media (max-height:860px) {
  :root { --ring-ry:44; --ring-rx:290; --ring-h:19rem; --ring-card:clamp(5.4rem,8vw,7rem); }
}
@media (max-width:640px) {
  :root { --ring-rx:112; --ring-ry:38; --ring-h:16rem; --ring-card:5.2rem; }
}

.netball--teach { position:relative; left:auto; top:auto; transform:none; width:min(13rem,26vw); margin:0 auto; }
.teach3__brain { position:relative; }
.teach3__chip { position:absolute; bottom:-0.4rem; }

/* ================= THE ROOM, IN 3D ================= */
#deck { perspective:1400px; perspective-origin:50% 42%; }
.studio { transform-style:preserve-3d; }

.studio__ceil {
  left:0; right:0; top:0; height:34%; border-radius:0 0 50% 50% / 0 0 18% 18%;
  background:
    radial-gradient(120% 150% at 20% -10%, color-mix(in srgb, var(--white) 22%, transparent), transparent 46%),
    radial-gradient(120% 150% at 80% -10%, color-mix(in srgb, var(--white) 22%, transparent), transparent 46%);
  box-shadow:none; opacity:1;
}
.slide--light .studio__ceil, .pack .studio__ceil {
  background:
    radial-gradient(120% 150% at 20% -10%, color-mix(in srgb, var(--white) 96%, transparent), transparent 48%),
    radial-gradient(120% 150% at 80% -10%, color-mix(in srgb, var(--white) 96%, transparent), transparent 48%);
}
.studio__strip {
  top:1.5%; width:clamp(2.4rem,5vw,4.4rem); height:0.5rem; border-radius:50%;
  background:var(--white); opacity:0.9; transform:none;
  box-shadow:0 0 26px 10px color-mix(in srgb, var(--white) 55%, transparent),
             0 14px 70px 30px color-mix(in srgb, var(--white) 22%, transparent);
}
.studio__strip--l { left:21%; }
.studio__strip--r { right:21%; left:auto; }

.studio__floor {
  left:-30%; right:-30%; bottom:0; height:42%;
  transform:perspective(700px) rotateX(62deg); transform-origin:50% 100%;
  background:linear-gradient(color-mix(in srgb, var(--white) 12%, transparent), transparent 60%),
             repeating-linear-gradient(90deg, transparent 0 11.5%, color-mix(in srgb, var(--white) 9%, transparent) 11.5% 11.6%);
}
.slide--light .studio__floor, .pack .studio__floor {
  background:linear-gradient(color-mix(in srgb, var(--white) 92%, transparent), color-mix(in srgb, var(--white) 55%, transparent) 60%),
             repeating-linear-gradient(90deg, transparent 0 11.5%, color-mix(in srgb, var(--black) 6%, transparent) 11.5% 11.6%);
}
.studio__gloss {
  left:0; right:0; bottom:40%; height:14%; filter:blur(10px);
  background:radial-gradient(ellipse 70% 100% at 50% 100%, color-mix(in srgb, var(--white) 18%, transparent), transparent 72%);
}
.slide--light .studio__gloss, .pack .studio__gloss {
  background:radial-gradient(ellipse 70% 100% at 50% 100%, color-mix(in srgb, var(--white) 95%, transparent), transparent 72%);
}

/* ---- walking into the next room ---- */
.studio.is-entering > *:not(.studio__rig) { animation:room-walk 0.75s cubic-bezier(0.22,0.9,0.28,1) both; }
.studio.is-up.is-entering > *:not(.studio__rig) { animation-name:room-walk-back; }
@keyframes room-walk {
  from { opacity:0; transform:translate3d(16vw,0,-320px) rotateY(-9deg); }
  to   { opacity:1; transform:none; }
}
@keyframes room-walk-back {
  from { opacity:0; transform:translate3d(-16vw,0,-320px) rotateY(9deg); }
  to   { opacity:1; transform:none; }
}
.studio.is-entering .studio__rig { animation:room-rig 0.75s ease-out both; }
.studio.is-up.is-entering .studio__rig { animation-name:room-rig-back; }
@keyframes room-rig { from { opacity:0.25; transform:translateX(7vw); } to { opacity:1; transform:none; } }
@keyframes room-rig-back { from { opacity:0.25; transform:translateX(-7vw); } to { opacity:1; transform:none; } }

@media (prefers-reduced-motion:reduce) {
  .studio.is-entering > *, .studio.is-entering .studio__rig { animation:none; }
  .ocard::before { animation:none; }
}

/* ================= 1 · plain rooms =================
   The drawn studio didn't read as a room, so it goes. Flat colour, a soft
   light from above, nothing else. */
.studio__ceil, .studio__strip, .studio__floor, .studio__gloss, .studio__dust { display:none !important; }
.studio__light {
  position:absolute; left:50%; top:0; transform:translateX(-50%);
  width:min(110rem,140%); height:70%;
  background:radial-gradient(ellipse 45% 100% at 50% 0%,
    color-mix(in srgb, var(--white) 9%, transparent), transparent 70%);
}
.slide--light .studio__light, .pack .studio__light {
  background:radial-gradient(ellipse 45% 100% at 50% 0%,
    color-mix(in srgb, var(--blue) 6%, transparent), transparent 70%);
}
#deck { perspective:none; }

/* ================= 9 · the flash, without the slide ================= */
.studio.is-entering > *:not(.studio__rig),
.studio.is-up.is-entering > *:not(.studio__rig) { animation:none !important; }
.studio.is-entering .studio__rig,
.studio.is-up.is-entering .studio__rig { animation:none !important; }
.studio.is-entering .studio__rig::after {
  content:''; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(105deg, transparent 35%,
    color-mix(in srgb, var(--white) 26%, transparent) 50%, transparent 65%);
  animation:room-sweep 0.85s ease-out forwards;
}
.slide--light .studio.is-entering .studio__rig::after,
.pack.is-entering .studio__rig::after {
  background:linear-gradient(105deg, transparent 35%,
    color-mix(in srgb, var(--blue) 14%, transparent) 50%, transparent 65%);
}

/* ================= 2 · We Teach, It Learn ================= */
.teach3 { align-items:start; }
.teach3__core { display:flex; flex-direction:column; align-items:center; }
/* the step label belongs above its own column, not floating over the header */
.teach3__core .teach3__step { order:-1; margin-bottom:0.8rem; }
.teach3__brain {
  position:relative; width:var(--ring-ball,17rem); aspect-ratio:1;
  display:grid; place-items:center; margin:0 auto;
}
.netball--teach {
  position:absolute; inset:0; left:50%; top:50%;
  transform:translate(-50%,-50%); width:100%; margin:0;
}
/* AI CORE sits under the ball, not on it */
.teach3__chip { position:static; margin-top:0.4rem; }
.teach3__note { margin-top:0.5rem; }

/* ================= 3 · Sovereign ================= */
#sovereign { align-items:center; }
#sovereign .sectmore {
  position:static; margin:1.2rem auto 0; display:inline-flex; align-self:center;
}

/* ================= 4 · Our Commitment ================= */
#commitment { display:flex; flex-direction:column; align-items:center; }
#commitment .thanks { order:3; margin-top:1.2rem; text-align:center; }
#commitment .orbit--wide { order:2; }
#commitment .overtitle, #commitment .overtitle__sub { order:1; }
/* This section lays its children out by `order`, so anything without one
   goes to the front — which is how the partner names and the certification
   line ended up printed ABOVE the headline. They belong with the thank-you,
   at the end. */
#commitment .partnerchips { order:4; margin-top:0.9rem; }
#commitment .certline { order:5; margin-top:0.35rem; }

/* ================= 5,6,7 · every card is the pack's card ================= */
.orbit--wide .orbit__node--logo { width:var(--ring-card); }
.orbit--wide .clogo-wrap {
  position:relative; display:block; width:100%; aspect-ratio:3/4;
  border-radius:14px; overflow:hidden; background:var(--white);
  box-shadow:0 20px 44px -24px rgba(10,2,3,0.5);
}
.orbit--wide .clogo-wrap::before {
  content:''; position:absolute; inset:-40% -120%; pointer-events:none; z-index:3;
  background:linear-gradient(74deg, transparent 42%, rgba(255,255,255,0.45) 50%, transparent 58%);
  animation:pack-shine 4.5s ease-in-out infinite;
}
.orbit--wide .clogo {
  position:absolute; inset:0 0 30% 0; width:auto; height:auto;
  border-radius:0; background:none; box-shadow:none;
}
.orbit--wide .clogo img { inset:16%; }
.orbit--wide .clogo__name {
  position:absolute; inset:auto 0 0 0; opacity:1; padding:0.5rem 0.55rem 0.7rem;
  font-size:0.66rem; line-height:1.3; color:var(--black); text-align:center;
}
/* the plain text cards match too */
.ocard--plain { aspect-ratio:3/4; display:flex; flex-direction:column; justify-content:center; }
.ocard--letter .ocard__letter { width:1.9rem; height:1.9rem; font-size:0.85rem; margin:0 auto 0.5rem; }
.ocard--plain .ocard__body { text-align:center; }
.ocard--sdg .ocard__media { aspect-ratio:1; }

/* ================= 8 · the pack room, plain white ================= */
.pack { background:var(--white); }
.pack .studio__light { background:radial-gradient(ellipse 45% 100% at 50% 0%,
  color-mix(in srgb, var(--blue) 5%, transparent), transparent 70%); }

/* the teach ball is exactly the pack ball */
.teach3__brain { width:min(19rem,42vw); }
.teach3__chip { display:inline-block; margin:0.6rem auto 0; }

/* the pack still carried its own width — one source of truth for all of them */
.orbit__node--pack { width:var(--ring-card) !important; }

/* ---- the cards were shrunk when the rings were unified; back to full size,
        driven from one variable so every ring stays in step ---- */
:root { --ring-card:clamp(8.5rem,11vw,12rem); --ring-rx:390; --ring-ry:64; --ring-h:27rem; }
@media (max-height:860px) { :root { --ring-card:clamp(7rem,9vw,9.5rem); --ring-rx:330; --ring-ry:50; --ring-h:22rem; } }
@media (max-width:640px)  { :root { --ring-card:6.6rem; --ring-rx:118; --ring-ry:40; --ring-h:17rem; } }

/* ---- the floating orbs come back; the rest of the room stays plain ---- */
.studio__dust { display:block !important; position:absolute; inset:0; overflow:hidden; }
.studio__dust i {
  position:absolute; display:block; border-radius:50%;
  background:radial-gradient(circle at 35% 35%,
    color-mix(in srgb, var(--white) 90%, transparent),
    color-mix(in srgb, var(--blue) 55%, transparent) 60%, transparent 72%);
  box-shadow:0 0 12px 3px color-mix(in srgb, var(--blue) 30%, transparent);
  animation:dust-rise linear infinite;
}
.slide--light .studio__dust i, .pack .studio__dust i {
  background:radial-gradient(circle at 35% 35%,
    color-mix(in srgb, var(--white) 95%, transparent),
    color-mix(in srgb, var(--blue) 40%, transparent) 60%, transparent 74%);
  box-shadow:0 0 14px 4px color-mix(in srgb, var(--blue) 16%, transparent);
}
@media (prefers-reduced-motion:reduce) { .studio__dust { display:none !important; } }

/* ================= 2 · every card the same size, text clipped ================
   A long role or detail used to stretch its card taller than its neighbours.
   Fixed proportions, and anything that doesn't fit ends in an ellipsis. */
.orbit__node--card .ocard, .orbit--wide .clogo-wrap {
  height:100%; display:flex; flex-direction:column;
}
.orbit__node--card, .orbit--wide .orbit__node--logo { aspect-ratio:3/4; }
.ocard__media { flex:0 0 58%; aspect-ratio:auto; }
.ocard__body { flex:1 1 auto; min-height:0; overflow:hidden; }
.ocard__body strong {
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden; line-height:1.25;
}
.ocard__body em {
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical;
  overflow:hidden;
}
.ocard--plain { aspect-ratio:auto; height:100%; }

/* ================= 3 · logos sit properly in their card ================= */
.orbit--wide .clogo { position:relative; inset:auto; flex:0 0 62%; width:100%; }
.orbit--wide .clogo img {
  position:absolute; inset:14%; width:auto; height:auto;
  max-width:none; max-height:none; object-fit:contain;
}
.orbit--wide .clogo__name {
  position:relative; inset:auto; flex:1 1 auto; min-height:0; overflow:hidden;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  padding:0.35rem 0.5rem 0.6rem;
}

/* ================= 1 · mobile keeps its words ================= */
@media (max-width:640px) {
  .ocard__body { padding:0.45rem 0.5rem 0.55rem; }
  .ocard__body strong { font-size:0.72rem; -webkit-line-clamp:2; }
  .ocard__body em { font-size:0.6rem; line-height:1.3; -webkit-line-clamp:2; }
  .orbit--wide .clogo__name { font-size:0.58rem; -webkit-line-clamp:2; }
  /* the ring nodes were scaled so far down at the back that text vanished */
  :root { --ring-min:0.5; }
  .rcard__tag { font-size:0.66rem; padding:1.6rem 0.6rem 0.5rem; }
  .certdisc__in { width:82%; }
}

/* An absolutely-positioned <img> with width:auto keeps its intrinsic size —
   insets alone will not shrink it, so the logos were being cropped. Giving it
   a definite box lets object-fit letterbox them properly. */
.clogo img, .clogo--lg img, .orbit--wide .clogo img {
  /* inset:auto must come BEFORE left/top — as a shorthand it resets them */
  position:absolute; inset:auto; left:50%; top:50%; transform:translate(-50%,-50%);
  width:74%; height:74%; max-width:74%; max-height:74%;
  object-fit:contain; object-position:center;
}

/* the three stages stack on a phone — as a row they forced the page wider */
@media (max-width:820px) {
  .teach3 { grid-template-columns:1fr; gap:1.2rem; width:min(30rem,92vw); }
  .teach3__col { width:100%; }
  .teach3__brain { width:min(11rem,44vw); }
  .teach3__feeds, .teach3__results { grid-template-columns:1fr 1fr; display:grid; }
  .teach3__feeds li, .teach3__res { font-size:0.74rem; padding:0.45rem 0.6rem; }
  .teach3__res em { font-size:0.68rem; }
  /* same on a phone: the pin carries the nav clearance, the section carries
     none, or the film starts partway down and leaves a line */
  .slide--teach { padding-top:0; }
}


/* ================= hero film bands =================
   Two on a desktop, four on a phone. Alternate bands run opposite ways and
   carry different slices of the list, so no film is ever on screen twice. */
.reel--mob { display:none; }
.reel--desk .reel__track { animation:reel-run 52s linear infinite; }
.reel--desk .reel__track--b { animation-name:reel-run-back; animation-duration:61s; }
.reel--desk .reel__track + .reel__track { margin-top:0.9rem; }
.reel--desk .rcard--film { width:clamp(12rem,30vh,20rem) !important; }

@keyframes reel-run-back { from { transform:translateX(0); } to { transform:translateX(-50%); } }

@media (max-width:820px) {
  .reel--desk { display:none; }
  .reel--mob  { display:block; }
  .reel--mob .reel__track { animation:reel-run 24s linear infinite; }
  .reel--mob .reel__track--b { animation-name:reel-run-back; animation-duration:29s; }
  .reel--mob .reel__track + .reel__track { margin-top:0.55rem; }
  .reel--mob .rcard--film { width:clamp(8rem,34vw,12rem) !important; }
  .reel--mob .rcard__tag { font-size:0.58rem; padding:1.2rem 0.5rem 0.4rem; }
}

/* Sized from viewport height so two rows plus the headline still land inside
   the room. Down from 52vh to 36vh: at the old size a card was 416px wide on
   a 1280x800 screen and under three of them fitted across, so the reel read
   as a handful of big pictures rather than a body of work. ~288px now, close
   to the size Dr KC marked up, and five across. Still two rows. */
.reel--desk .rcard--film { width:clamp(14rem,36vh,26rem) !important; }
.reel--desk .reel__track + .reel__track { margin-top:1.1rem; }
.reel--desk .rcard__tag { font-size:0.86rem; padding:2.6rem 1rem 0.9rem; }

/* ---- the film panel: no black bars, and a way into the chapter ----
   max-height was capping the height while the width stayed fixed, so the box
   stopped being 16:9 and the video letterboxed inside it. Constraining the
   width by the available height instead keeps the box exactly 16:9. */
.reelopen.is-film .reelopen__panel {
  width:min(92rem, 96vw, 150vh);
  aspect-ratio:16/9; height:auto; max-height:none;
  background:#000;
}
.reelopen__video, .reelopen__video video, .reelopen__video iframe {
  position:absolute; inset:0; width:100%; height:100%; display:block; border:0;
}
.reelopen__video video { object-fit:contain; background:#000; }

/* the chapter button rides the bottom-right of the player */
.reelopen.is-film .reelopen__go {
  display:inline-block; pointer-events:auto;
  position:absolute; right:clamp(1rem,3vw,2rem); bottom:clamp(1rem,3vw,1.6rem);
  background:var(--blue); color:var(--white); border:0; border-radius:999px;
  padding:0.6rem 1.3rem; font-weight:700; font-size:0.88rem; text-decoration:none;
  box-shadow:0 10px 26px -8px rgba(0,0,0,0.6);
  transition:transform 0.2s ease, background 0.2s ease;
}
.reelopen.is-film .reelopen__go:hover { background:#0a67d6; transform:translateY(-2px); }
.reelopen.is-film .reelopen__body {
  padding:2.6rem clamp(1rem,3vw,2rem) 1rem;
  padding-right:clamp(10rem,22vw,16rem);      /* clear of the button */
}

/* The player had z-index:1 and the caption none, so the chapter button was
   painting underneath the video. It also has to clear the player's own
   controls along the bottom — so it sits top-left, opposite the close. */
.reelopen.is-film .reelopen__body { z-index:4; }
.reelopen.is-film .reelopen__go {
  z-index:5; top:clamp(0.9rem,2.5vw,1.4rem); left:clamp(0.9rem,2.5vw,1.4rem);
  right:auto; bottom:auto;
  background:color-mix(in srgb, var(--black) 55%, transparent);
  backdrop-filter:blur(8px);
  border:1.5px solid rgba(255,255,255,0.5);
}
.reelopen.is-film .reelopen__go:hover { background:var(--blue); border-color:var(--blue); }
/* the title strip drops to the bottom-left, clear of the controls */
.reelopen.is-film .reelopen__body {
  inset:auto 0 0 0; padding:2.4rem clamp(1rem,3vw,2rem) 3.4rem;
  padding-right:clamp(6rem,14vw,10rem);
}

/* ================= result states =================
   Each result carries its own colour, so the story reads at a glance:
   red found a problem, orange needs a person, yellow is still learning,
   green is closed out. */
.teach3__res {
  --st:#8ec5ff;                                  /* neutral, before JS runs */
  border-color:color-mix(in srgb, var(--st) 45%, transparent);
  background:color-mix(in srgb, var(--st) 9%, transparent);
  transition:border-color 0.45s ease, background 0.45s ease, box-shadow 0.45s ease;
}
.teach3__res.is-detected { --st:#ff5a5a; }
.teach3__res.is-alert    { --st:#ffa53d; }
.teach3__res.is-learning { --st:#ffd54a; }
.teach3__res.is-resolved { --st:#3ddc97; }

.teach3__res strong { color:var(--st); }
.teach3__state {
  display:block; margin-top:0.25rem; font-size:0.68rem; font-weight:700;
  letter-spacing:0.06em; text-transform:uppercase; color:var(--st); opacity:0.85;
}
/* the flash as a result changes */
.teach3__res.is-turning {
  animation:res-flip 0.55s ease-out;
  box-shadow:0 0 0 1px color-mix(in srgb, var(--st) 55%, transparent),
             0 0 22px -2px color-mix(in srgb, var(--st) 65%, transparent);
}
@keyframes res-flip {
  0%   { opacity:0.25; transform:translateX(-8px); }
  60%  { opacity:1;    transform:translateX(2px); }
  100% { opacity:1;    transform:none; }
}
/* the old fixed states are gone */
.teach3__res--ok, .teach3__res--fix, .teach3__fix { all:unset; }
.teach3__res { animation:none; }

/* ================= the knowledge graph =================
   Eight chapters wired together, with every published Story Card hanging off
   the chapters it touches. Colour carries the meaning — see .nglegend. */
.netgraph { position:relative; width:100%; height:100%; }
.netgraph__svg { width:100%; height:100%; display:block; overflow:visible; }
.netgraph__links line { stroke:#8ec5ff; stroke-width:0.5; transition:stroke 0.3s ease; }
.netgraph__links line.is-charged {
  stroke:#fff; stroke-width:1.3;
  filter:drop-shadow(0 0 4px #fff) drop-shadow(0 0 10px #8ec5ff);
}
.netgraph__halo { animation:nb-breathe 5s ease-in-out infinite; transform-origin:center; }
.netgraph__links line.is-spoke { stroke:#0078FF; stroke-width:0.35; }

/* ---- the ball: a shell to sit inside, a core to sit at the centre ----
   A scatter of dots reads as a scatter. The same dots with a pulsing middle
   and a faint outer shell read as one object turning.
   A page that doesn't ship the graph data gets neither — an empty shell
   pinging away with nothing inside it just looks broken. */
.netgraph:not(.is-built) .netgraph__shell,
.netgraph:not(.is-built) .netgraph__halo,
.netgraph:not(.is-built) .netgraph__ping { display:none; }
.netgraph__shell {
  fill:none; stroke:#8ec5ff; stroke-width:0.35; stroke-dasharray:2 5; opacity:0.22;
  transform-box:fill-box; transform-origin:center;
  animation:ng-shell 26s linear infinite;
}
@keyframes ng-shell { to { transform:rotate(360deg); } }
.netgraph__ping {
  fill:none; stroke:#8ec5ff; stroke-width:0.8; opacity:0;
  transform-box:fill-box; transform-origin:center;
  animation:ng-ping 3.4s ease-out infinite;
}
.netgraph__ping--2 { animation-delay:1.7s; }
@keyframes ng-ping {
  0%   { transform:scale(0.35); opacity:0.55; }
  70%  { opacity:0.12; }
  100% { transform:scale(2.4);  opacity:0; }
}
/* ---- every dot is an orb, not a disc ----
   No outline anywhere: a wide coloured glow that fades to nothing, with a hot
   white middle. A flat circle that brightens reads as a light switching on; a
   glow that swells reads as the thing itself charging, which is what a signal
   arriving should look like.

   `color` carries the chapter hue, so one rule per state lights every chapter
   in its own colour instead of one rule per state per chapter. */
.ngnode {
  color:#8ec5ff;
  transform-box:fill-box; transform-origin:center;
}
/* the glow has no edge to aim at, so an invisible circle carries the click */
.ngdot { fill:none; pointer-events:all; }
.ngdot__glow {
  fill:url(#ngG-story); pointer-events:none;
  opacity:0.95; transition:opacity 0.35s ease;
}
.ngdot__hot {
  fill:url(#ngG-hot); pointer-events:none;
  opacity:0.45; transition:opacity 0.35s ease;
}

.ngnode.is-active { color:#3ddc97; }
.ngnode.is-active .ngdot__glow { fill:url(#ngG-nature); }
.ngnode.is-past   { color:#8ec5ff; }
.ngnode.is-active .ngdot__hot { opacity:0.6; }
.ngnode:not(.is-big) .ngdot__hot { opacity:0.3; }

/* the core: a white heart in a blue glow, and it breathes */
.ngnode.is-core { color:#2f9dff; animation:ng-core 2.6s ease-in-out infinite; }
.ngnode.is-core .ngdot__glow { fill:url(#ngG-core); }
.ngnode.is-core .ngdot__hot { opacity:0.95; }
@keyframes ng-core {
  0%,100% { transform:scale(1);    opacity:0.94; }
  50%     { transform:scale(1.14); opacity:1; }
}

/* a charge arriving: the orb swells and its middle goes white */
.ngnode.is-lit { animation:ng-hit 0.7s cubic-bezier(0.2,0.9,0.3,1.2); }
.ngnode.is-lit .ngdot__hot { opacity:1; transition:opacity 0.1s ease; }
.ngnode.is-lit .ngdot__glow { opacity:1; transition:opacity 0.1s ease; }
@keyframes ng-hit {
  0%   { transform:scale(1); }
  26%  { transform:scale(1.55); }
  100% { transform:scale(1); }
}

/* only the live copy invites a click */
.netgraph--live .ngnode { cursor:pointer; }
.netgraph--live .ngnode:hover .ngdot__hot,
.netgraph--live .ngnode:focus-visible .ngdot__hot { opacity:1; }
.netgraph--live .ngnode:focus-visible { outline:none; }

/* The label. It sits over a near-black panel, so it must set its own colour —
   inherited text colour here is the page's, which is nearly black too. */
.netgraph__tip {
  position:absolute; transform:translate(-50%,-100%); pointer-events:none; z-index:5;
  background:color-mix(in srgb, #06111f 94%, transparent);
  border:1px solid rgba(140,197,255,0.32); border-radius:10px;
  padding:0.5rem 0.75rem; max-width:15rem; text-align:center;
  color:var(--white);
  box-shadow:0 10px 26px -10px rgba(0,0,0,0.8), 0 0 24px -8px rgba(0,120,255,0.6);
}
.netgraph__tip.is-below { transform:translate(-50%,0); }
.netgraph__tip[hidden] { display:none; }
.netgraph__tip strong { display:block; font-size:0.78rem; line-height:1.3; color:var(--white); }
.netgraph__tip em {
  display:block; font-style:normal; font-size:0.66rem; line-height:1.35;
  opacity:0.7; margin-top:0.15rem; color:var(--white);
}
/* which chapters this thing belongs to, in each chapter's own colour */
.ngtip__tags {
  display:flex; flex-wrap:wrap; justify-content:center; gap:0.25rem; margin-top:0.4rem;
}
.ngtip__tags b {
  font-size:0.58rem; font-weight:700; letter-spacing:0.03em; padding:0.1rem 0.4rem;
  border-radius:999px; color:var(--c);
  background:color-mix(in srgb, var(--c) 18%, transparent);
  border:1px solid color-mix(in srgb, var(--c) 45%, transparent);
}
.ngtip__go {
  display:block; margin-top:0.35rem; font-size:0.56rem; letter-spacing:0.08em;
  text-transform:uppercase; color:#8ec5ff; opacity:0.8;
}

/* what the colours mean */
.nglegend {
  list-style:none; display:flex; justify-content:center; flex-wrap:wrap;
  gap:0.4rem 0.9rem; margin-top:0.7rem; font-size:0.64rem; letter-spacing:0.04em;
}
.nglegend li { display:flex; align-items:center; gap:0.35rem; opacity:0.75; }
.nglegend span { width:0.5rem; height:0.5rem; border-radius:50%; display:block; }
.nglegend .is-chapter span { background:#fff; }
.nglegend .is-active  span { background:#3ddc97; box-shadow:0 0 6px #3ddc97; }
.nglegend .is-past    span { background:#8ec5ff; }
@media (prefers-reduced-motion:reduce) { .netgraph__halo { animation:none; } }

/* the cost each trade removes, stated under its name */
.teach3__instead {
  display:block; font-size:0.66rem; line-height:1.35; opacity:0.5;
  margin:0.1rem 0 0.35rem;
}
/* the card's own parts now set their own sizes — see .teach3__layer below */
.teach3__res em { font-size:0.78rem; }

/* ================= the Golden Circle results =================
   Colour follows the chapter, not the state — learn the palette once and it
   reads the same everywhere on the site. */
.teach3__res {
  --neu:#8ec5ff;
  border-color:color-mix(in srgb, var(--neu) 48%, transparent);
  background:color-mix(in srgb, var(--neu) 9%, transparent);
  transition:border-color 0.5s ease, background 0.5s ease, box-shadow 0.5s ease;
}
.teach3__res .teach3__layer {
  display:block; font-size:0.6rem; font-weight:700; letter-spacing:0.14em;
  text-transform:uppercase; line-height:1.35;
  color:color-mix(in srgb, var(--neu) 70%, var(--white)); opacity:0.7;
}
/* the promise itself — fixed, and the biggest thing in the card */
.teach3__promise {
  display:block; font-size:1rem; font-weight:800; line-height:1.25;
  color:var(--white); margin-top:0.2rem;
}
.teach3__pline {
  display:block; font-size:0.7rem; line-height:1.4; opacity:0.62;
  margin:0.2rem 0 0.45rem;
}
/* and the chapter currently proving it */
.teach3__proof {
  display:flex; align-items:center; gap:0.45rem; flex-wrap:wrap;
  padding-top:0.45rem; border-top:1px solid color-mix(in srgb, var(--neu) 26%, transparent);
}
.teach3__neu {
  font-size:0.82rem; font-weight:700; color:var(--neu);
}
.teach3__trade {
  display:inline-block; margin:0; padding:0.12rem 0.5rem;
  border-radius:999px; font-size:0.66rem; font-weight:700; letter-spacing:0.06em;
  text-transform:uppercase;
  background:color-mix(in srgb, var(--neu) 20%, transparent);
  color:color-mix(in srgb, var(--neu) 80%, var(--white));
}
.teach3__res em { display:block; font-style:normal; font-size:0.74rem; line-height:1.45; opacity:0.78; margin-top:0.3rem; }
.teach3__res.is-turning {
  animation:res-flip 0.6s ease-out;
  box-shadow:0 0 0 1px color-mix(in srgb, var(--neu) 60%, transparent),
             0 0 26px -2px color-mix(in srgb, var(--neu) 65%, transparent);
}

/* ---- the lightning between the three columns ----
   Drawn in a single overlay that spans the whole row, so a bolt can start on
   a signal, cross into the ball, and leave for a result without any clipping. */
.teach3__bolts {
  position:absolute; inset:0; width:100%; height:100%;
  pointer-events:none; z-index:6; overflow:visible;
}
.bolt {
  fill:none; stroke:#8ec5ff; stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round;
  filter:drop-shadow(0 0 4px currentColor);
  opacity:1; transition:opacity 0.3s ease;
}
.bolt--glow { stroke-width:6; opacity:0.22; filter:blur(3px); }
.bolt.is-gone { opacity:0; }
.bolt__head { filter:drop-shadow(0 0 6px #fff) drop-shadow(0 0 14px currentColor); }
@media (prefers-reduced-motion:reduce) { .teach3__bolts { display:none; } }

/* ---- the chain: a signal fires, the core takes it, a result lands ---- */
.teach3__feeds li.is-sending {
  border-color:#fff;
  box-shadow:0 0 0 1px rgba(255,255,255,0.5), 0 0 20px -2px #8ec5ff;
  animation:feed-fire 0.7s ease-out;
}
@keyframes feed-fire {
  0%   { transform:translateX(0); }
  35%  { transform:translateX(20px); }
  100% { transform:translateX(0); }
}
.netgraph.is-charging .netgraph__halo { opacity:1; transform:scale(1.16); }
.netgraph.is-charging .netgraph__links line { stroke:#fff; opacity:0.8 !important; }
.netgraph__halo, .netgraph__links line { transition:opacity 0.3s ease, transform 0.3s ease, stroke 0.3s ease; }

/* the graph's own nodes take the chapter palette too */
/* `color` is what the dome's solid dots use; the glow picks the matching
   gradient. Both come off the same class, so they can never disagree. */
.ngnode.is-neumotion  { color:#2f8fff; } .ngnode.is-neumotion  .ngdot__glow { fill:url(#ngG-motion); }
.ngnode.is-neunature  { color:#3ddc97; } .ngnode.is-neunature  .ngdot__glow { fill:url(#ngG-nature); }
.ngnode.is-neucity    { color:#ffa53d; } .ngnode.is-neucity    .ngdot__glow { fill:url(#ngG-city); }
.ngnode.is-neufactory { color:#b98cff; } .ngnode.is-neufactory .ngdot__glow { fill:url(#ngG-factory); }
.ngnode.is-neuslm     { color:#38d9d3; } .ngnode.is-neuslm     .ngdot__glow { fill:url(#ngG-slm); }
.ngnode.is-neutalents { color:#ff7ac8; } .ngnode.is-neutalents .ngdot__glow { fill:url(#ngG-talents); }
.ngnode.is-neustudio  { color:#ffd54a; } .ngnode.is-neustudio  .ngdot__glow { fill:url(#ngG-studio); }
.ngnode.is-neustory   { color:#8ec5ff; } .ngnode.is-neustory   .ngdot__glow { fill:url(#ngG-story); }

/* ================= the graph, opened =================
   The copy in the section is a doorway — the dots there are far too small to
   hit. Pressing it opens the same graph at full size, with zoom. */
.netgraph--door { cursor:zoom-in; transition:transform 0.3s ease, filter 0.3s ease; }
.netgraph--door:hover, .netgraph--door:focus-visible { transform:scale(1.04); filter:brightness(1.15); }
.netgraph--door:focus-visible { outline:2px solid #8ec5ff; outline-offset:6px; border-radius:50%; }

.gstage { position:fixed; inset:0; z-index:180; opacity:0; transition:opacity 0.26s ease; }
.gstage.is-open { opacity:1; }
.gstage[hidden] { display:none; }
.gstage__scrim {
  position:absolute; inset:0;
  background:color-mix(in srgb, var(--black) 78%, transparent); backdrop-filter:blur(10px);
}
.gstage__panel {
  position:absolute; inset:clamp(0.6rem,3vw,2.4rem);
  display:flex; flex-direction:column; border-radius:24px; overflow:hidden;
  background:color-mix(in srgb, #0b1b2e 92%, transparent);
  border:1px solid rgba(255,255,255,0.14);
  box-shadow:0 50px 100px -30px rgba(0,0,0,0.8);
  transform:scale(0.96); transition:transform 0.32s cubic-bezier(0.2,0.9,0.3,1.2);
}
.gstage.is-open .gstage__panel { transform:none; }
.gstage__bar {
  position:relative;
  display:flex; align-items:center; gap:1rem; flex-wrap:wrap;
  padding:0.8rem clamp(0.9rem,2.4vw,1.6rem);
  border-bottom:1px solid rgba(255,255,255,0.12); color:var(--white);
}
/* the line belongs in the middle of the bar, not tucked in the corner */
.gstage__title {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  margin:0; white-space:nowrap; pointer-events:none;
}
.gstage__bar .nglegend { margin:0; margin-right:auto; }

/* ---- the title, shiny and a little bit digital ----
   One gradient sweeping across the letters, and two chromatic ghosts that
   twitch every few seconds — enough to read as a machine, not a poster. */
.gtitle {
  position:relative; display:inline-block;
  font-weight:800; font-size:clamp(0.78rem,1.5vw,1.02rem);
  letter-spacing:0.22em; text-transform:uppercase;
  background:linear-gradient(100deg,
    #6fb2ff 0%, #ffffff 16%, #cfe6ff 26%, #6fb2ff 40%, #6fb2ff 100%);
  background-size:260% 100%;
  -webkit-background-clip:text; background-clip:text; color:transparent;
  animation:gtitle-shine 6s linear infinite;
}
@keyframes gtitle-shine { to { background-position:-160% 0; } }
.gtitle::before, .gtitle::after {
  content:attr(data-text); position:absolute; left:0; top:0;
  background:none; -webkit-background-clip:border-box; background-clip:border-box;
  pointer-events:none;
}
.gtitle::before { color:#38d9d3; animation:gtitle-glitch-a 5.5s steps(1) infinite; }
.gtitle::after  { color:#ff7ac8; animation:gtitle-glitch-b 5.5s steps(1) infinite; }
@keyframes gtitle-glitch-a {
  0%,92%,100% { opacity:0; transform:none; clip-path:inset(0 0 100% 0); }
  93%         { opacity:0.55; transform:translate(-1.5px,-1px); clip-path:inset(0 0 58% 0); }
  95%         { opacity:0.4;  transform:translate(1.5px,1px);   clip-path:inset(46% 0 24% 0); }
  97%         { opacity:0;    clip-path:inset(0 0 100% 0); }
}
@keyframes gtitle-glitch-b {
  0%,92%,100% { opacity:0; transform:none; clip-path:inset(100% 0 0 0); }
  94%         { opacity:0.5; transform:translate(2px,1px);  clip-path:inset(52% 0 0 0); }
  96%         { opacity:0.35; transform:translate(-2px,0);  clip-path:inset(22% 0 44% 0); }
  98%         { opacity:0;   clip-path:inset(100% 0 0 0); }
}
@media (max-width:640px) {
  .gstage__title { position:static; transform:none; order:-1; width:100%; text-align:center; }
  .gtitle { letter-spacing:0.12em; }
}
@media (prefers-reduced-motion:reduce) {
  .gtitle { animation:none; }
  .gtitle::before, .gtitle::after { display:none; }
}
.gstage__zoom { display:flex; align-items:center; gap:0.4rem; }
.gstage__zoom button {
  width:1.9rem; height:1.9rem; border-radius:50%; cursor:pointer;
  border:1px solid rgba(255,255,255,0.3); background:none; color:var(--white);
  font-size:1rem; line-height:1;
}
.gstage__zoom button:hover { background:var(--blue); border-color:var(--blue); }
.gstage__zoom output { font-size:0.78rem; opacity:0.7; min-width:3rem; text-align:center; }
.gstage__close {
  width:2.2rem; height:2.2rem; border-radius:50%; cursor:pointer; font-size:1.2rem;
  border:0; background:rgba(255,255,255,0.12); color:var(--white);
}
.gstage__close:hover { background:var(--blue); }

/* ---- ask it out loud ----
   A pill rather than a bare icon, because a lone microphone glyph does not
   tell anybody what it wants them to SAY, and this one needs a set phrase. */
/* `hidden` is only a UA `display: none`, so the display below would have beaten
   it — and the microphone would have sat there looking pressable on every
   browser that cannot do speech at all, which is the one case the attribute
   exists to cover. */
.gmic[hidden] { display:none; }
.gmic {
  display:flex; align-items:center; gap:0.42rem; cursor:pointer;
  font:800 0.72rem 'Inter',sans-serif; letter-spacing:0.03em;
  padding:0.36rem 0.85rem 0.36rem 0.6rem; border-radius:999px;
  color:var(--white); border:1.5px solid rgba(255,255,255,0.28);
  background:rgba(255,255,255,0.08);
  transition:background 0.18s ease, border-color 0.18s ease, transform 0.12s ease;
}
.gmic:hover { background:var(--blue); border-color:var(--blue); transform:translateY(-1px); }
.gmic__ico { width:1.05rem; height:1.05rem; flex:none; }
.gmic__say { white-space:nowrap; }

/* live: red, and breathing, so there is never a doubt the room is being heard */
.gmic.is-live {
  background:#e0245e; border-color:#ff5a86; color:#fff;
  animation:gmic-live 1.5s ease-in-out infinite;
}
@keyframes gmic-live {
  0%, 100% { box-shadow:0 0 0 0 rgba(224,36,94,0.55); }
  70%      { box-shadow:0 0 0 0.5rem rgba(224,36,94,0); }
}
@media (prefers-reduced-motion: reduce) { .gmic.is-live { animation:none; } }

/* what it heard, and what it did about it */
.gvoice {
  margin:0.3rem clamp(0.9rem,2.4vw,1.6rem) 0; padding:0.5rem 0.85rem;
  border-radius:12px; font-size:0.8rem; line-height:1.45; text-align:center;
  border:1px solid rgba(255,255,255,0.14); background:rgba(255,255,255,0.05);
  color:rgba(255,255,255,0.92);
}
.gvoice span { opacity:0.62; }
.gvoice.is-live { border-color:rgba(255,90,134,0.5); background:rgba(224,36,94,0.14); }
.gvoice.is-ok   { border-color:rgba(120,220,170,0.45); background:rgba(60,200,140,0.12); }
.gvoice.is-miss { border-color:rgba(255,200,120,0.45); background:rgba(255,170,60,0.12); }
/* The ball must sit dead centre with room to zoom into. Sizing it from the
   HEIGHT is what does it: height is the scarce dimension on a laptop, and a
   square sized off the width overflowed the panel and pushed the graph down
   and out of the frame. */
/* ---- the chapter picker ---- */
.gpick {
  display:flex; flex-wrap:wrap; gap:0.4rem; justify-content:center;
  padding:0.7rem clamp(0.9rem,2.4vw,1.6rem) 0.2rem;
}
.gpick__btn, .gpick__all {
  --c:#8ec5ff;
  font:800 0.72rem 'Inter',sans-serif; letter-spacing:0.03em; cursor:pointer;
  padding:0.35rem 0.8rem; border-radius:999px; color:var(--white);
  border:1.5px solid color-mix(in srgb, var(--c) 55%, transparent);
  background:color-mix(in srgb, var(--c) 14%, transparent);
  transition:background 0.18s ease, border-color 0.18s ease, transform 0.12s ease, opacity 0.18s ease;
}
.gpick__btn::before {
  content:''; display:inline-block; width:0.5rem; height:0.5rem; border-radius:50%;
  background:var(--c); margin-right:0.4rem; vertical-align:middle;
  box-shadow:0 0 8px var(--c);
}
.gpick__btn:hover, .gpick__all:hover { transform:translateY(-1px); border-color:var(--c); }
.gpick__btn.is-on {
  background:var(--c); border-color:var(--c); color:#08111d;
  box-shadow:0 0 18px -4px var(--c);
}
.gpick__btn.is-on::before { background:#08111d; box-shadow:none; }
/* once something is picked, the unpicked buttons step back too */
.gpick.has-pick .gpick__btn:not(.is-on) { opacity:0.42; }
.gpick__all { --c:#ffffff; opacity:0.55; }
.gpick.has-pick .gpick__all { opacity:1; }

/* a dot outside the picked chapters: grey, quiet, and not clickable */
.ngnode.is-off { opacity:0.3; }
.ngnode.is-off .ngdot { pointer-events:none; }
.ngnode.is-off .ngdot__glow { fill:url(#ngG-mute); }
.ngnode.is-off .ngdot__hot { opacity:0; }
.netgraph__links line.is-off { stroke:#7c8ba1; opacity:0.05; }

.gstage__hint {
  text-align:center; font-size:0.7rem; letter-spacing:0.04em; color:var(--white);
  opacity:0.45; padding:0 1rem 0.8rem;
}
.gstage__view {
  flex:1; min-height:0; overflow:hidden; cursor:grab; touch-action:none;
  display:flex; align-items:center; justify-content:center;
}
.gstage__view.is-turning { cursor:grabbing; }
.netgraph--stage {
  height:94%; width:auto; max-width:94%; aspect-ratio:1; flex:none;
  transition:transform 0.22s ease; transform-origin:center;
}
@media (prefers-reduced-motion:reduce) {
  .gstage, .gstage__panel, .netgraph--stage { transition:none; }
}

/* =========================================================================
   THE BITS BACKSTAGE OWNS
   Every rule here styles something that comes out of the database rather than
   out of a template — a kicker, a row of chips, a certification line. They
   are collected together because they share one property: if a person clears
   the field in Backstage, the element is not rendered at all, so none of them
   may reserve space of their own.
   ========================================================================= */

/* the small line above the hero headline */
.herokick {
  position:relative; z-index:2; color:var(--white); opacity:0.86;
  font-weight:700; letter-spacing:0.16em; text-transform:uppercase;
  font-size:clamp(0.66rem,1.4vw,0.8rem); margin-bottom:0.7rem;
  text-shadow:0 2px 14px rgba(0,0,0,0.55);
}

/* the domain labels under "We Teach, It Learn", and the partners under the
   thank-you line — same chip, two colour schemes */
.domainchips, .partnerchips {
  list-style:none; display:flex; flex-wrap:wrap; justify-content:center;
  gap:0.4rem; margin:0.8rem 0 0; padding:0;
}
.domainchips li, .partnerchips li {
  font-size:0.72rem; font-weight:700; letter-spacing:0.06em;
  border-radius:999px; padding:0.3rem 0.8rem; white-space:nowrap;
}
.domainchips li { color:var(--white); background:rgba(255,255,255,0.12); border:1px solid rgba(255,255,255,0.24); }
.partnerchips { position:relative; z-index:4; }
.partnerchips li { color:var(--blue-deep); background:var(--blue-pale); border:1px solid color-mix(in srgb, var(--blue) 22%, transparent); }

.certline {
  position:relative; z-index:4; text-align:center; margin-top:0.7rem;
  font-size:0.74rem; letter-spacing:0.04em; opacity:0.62;
}

/* the closing note under the sovereign ring */
.sovcompact {
  position:relative; z-index:4; text-align:center;
  max-width:44rem; margin:1.1rem auto 0; font-size:0.86rem; line-height:1.55;
  color:var(--white); opacity:0.78;
}
.sovcompact b {
  display:block; font-size:0.7rem; letter-spacing:0.14em; text-transform:uppercase;
  opacity:0.75; margin-bottom:0.25rem;
}

/* the signature line above the footer's base row */
.pgfoot__sig {
  text-align:center; padding:0 clamp(1rem,4vw,3rem) 0.4rem;
  display:flex; flex-direction:column; gap:0.2rem;
}
.pgfoot__sig b { font-size:1.02rem; }
.pgfoot__sig span { font-size:0.8rem; opacity:0.72; }

/* =========================================================================
   THE BACKLIGHT
   Every film in section 1 is lit from behind in the colour of the chapter
   that made it. It is the same palette as the dots on the knowledge ball and
   the Golden Circle cards, so a person learns it once and it reads the same
   everywhere: orange is NEUCity, green is NEUNature, blue is NEUMotion.

   It has to be a box-shadow rather than a glowing layer: .rcard clips its
   children so it can round its corners over the thumbnail, and anything drawn
   inside would be cut off at the very edge the glow needs to escape from.
   A box-shadow is painted outside the border box and behind the element,
   which is exactly what a backlight is.
   ========================================================================= */
[data-neu="neucity"]    { --neu:#ffa53d; }
[data-neu="neunature"]  { --neu:#3ddc97; }
[data-neu="neumotion"]  { --neu:#2f8fff; }
[data-neu="neufactory"] { --neu:#b98cff; }
[data-neu="neuslm"]     { --neu:#38d9d3; }
[data-neu="neutalents"] { --neu:#ff7ac8; }
[data-neu="neustudio"]  { --neu:#ffd54a; }
[data-neu="neustory"]   { --neu:#8ec5ff; }

/* The reel needs more air than it had, in both directions.
   Sideways: with the old gap the haze from one card ran straight into its
   neighbour's and a row read as one smudge rather than as separate films.
   Vertically it was worse than tight — it was cut off. The reel clips its
   own overflow so the strip can run off the edges of the screen, and with no
   vertical padding the top and bottom rows sat flush against that clip, so
   the half of each glow that pointed out of the reel was simply not drawn.
   The padding is the room the light needs INSIDE the clipping box. */
.slide--hero .reel { padding-block: clamp(2.5rem, 5vh, 4.5rem); }
/* Tighter than it was, to go with the smaller cards — at a 41px gap the row
   looked sparser after the shrink than it had before it. */
.reel--desk .reel__track, .reel--mob .reel__track { gap: clamp(0.9rem, 1.9vw, 1.6rem); }
.reel--desk .reel__track + .reel__track { margin-top: 2.4rem; }
.reel--mob .reel__track + .reel__track { margin-top: 1.4rem; }

.rcard--film[data-neu] {
  --edge: color-mix(in srgb, var(--neu) 92%, transparent);
  box-shadow:
    0 18px 40px -20px rgba(0, 0, 0, 0.75),                      /* on the page  */
    0 0 0 2px var(--edge),                                      /* the filament */
    0 0 22px -1px color-mix(in srgb, var(--neu) 72%, transparent),   /* the bloom */
    0 0 58px 6px color-mix(in srgb, var(--neu) 38%, transparent),    /* the haze  */
    inset 0 0 0 1px color-mix(in srgb, var(--neu) 45%, transparent);
}

/* Hover lifts the card and turns the light up. Both stops are on the same
   transition the card already had, so it stays one movement. */
.rcard--film[data-neu]:hover,
.rcard--film[data-neu]:focus-visible {
  transform: translateY(-6px);
  box-shadow:
    0 26px 52px -18px rgba(0, 0, 0, 0.8),
    0 0 0 2px var(--neu),
    0 0 30px 1px color-mix(in srgb, var(--neu) 88%, transparent),
    0 0 88px 12px color-mix(in srgb, var(--neu) 52%, transparent),
    inset 0 0 0 1px color-mix(in srgb, var(--neu) 70%, transparent);
}

/* The chapter's name, small, in its own colour — the glow says "these
   two belong together", the word says which one it is. Colour alone is not
   an answer for anyone who cannot separate the greens from the blues. */
.rcard__neu {
  position: absolute; left: 0.6rem; top: 0.6rem; z-index: 2;
  font-size: 0.6rem; font-weight: 800; letter-spacing: 0.08em;
  text-transform: uppercase; line-height: 1;
  padding: 0.26rem 0.5rem; border-radius: 999px;
  color: color-mix(in srgb, var(--neu, #8ec5ff) 88%, var(--white));
  background: color-mix(in srgb, #0A0203 62%, transparent);
  border: 1px solid color-mix(in srgb, var(--neu, #8ec5ff) 55%, transparent);
  backdrop-filter: blur(4px);
}
/* On a phone a film card is about 128px wide, and a 58px haze around it is
   most of the card again — it stops reading as a backlight and starts reading
   as fog. Same light, scaled to the object. */
@media (max-width: 640px) {
  .reel--mob .rcard__neu { font-size: 0.5rem; padding: 0.2rem 0.38rem; left: 0.4rem; top: 0.4rem; }
  .reel--mob .rcard--film[data-neu] {
    box-shadow:
      0 12px 26px -14px rgba(0, 0, 0, 0.75),
      0 0 0 1.5px var(--edge),
      0 0 12px -2px color-mix(in srgb, var(--neu) 70%, transparent),
      0 0 30px 2px color-mix(in srgb, var(--neu) 34%, transparent),
      inset 0 0 0 1px color-mix(in srgb, var(--neu) 45%, transparent);
  }
}

/* The panel a film opens into is lit by the same chapter, so pressing a card
   carries its colour with it instead of dropping into a neutral box. */
.reelopen__panel[data-neu] {
  box-shadow:
    0 40px 90px -20px rgba(0, 0, 0, 0.7),
    0 0 0 1px color-mix(in srgb, var(--neu) 50%, transparent),
    0 0 60px 2px color-mix(in srgb, var(--neu) 24%, transparent);
}
/* reelbox.css lands after this file and styles these two through
   `.reelopen .rbox--go .reelopen__go`, which is exactly as specific as the
   obvious selector here — so the later file won and the button stayed blue
   inside a green panel. Matching its shape and adding the panel puts this
   ahead of it on specificity rather than on load order. */
.reelopen .reelopen__panel[data-neu] .rbox--go .reelopen__go,
.reelopen.is-film .reelopen__panel[data-neu] .rbox--go .reelopen__go {
  background: var(--neu); color: #0A0203; border-color: transparent;
}
.reelopen .reelopen__panel[data-neu] .rbox--go .reelopen__go:hover {
  background: color-mix(in srgb, var(--neu) 82%, var(--white));
  border-color: transparent;
}
.reelopen .reelopen__panel[data-neu] .rbox--info .reelopen__kind { color: var(--neu); }

/* A reel that is not moving is not a reel, and a glow that big on a phone in
   a dark room is a lot. Reduced motion keeps the colour and drops the haze. */
@media (prefers-reduced-motion: reduce) {
  .rcard--film[data-neu] {
    box-shadow:
      0 18px 40px -20px rgba(0, 0, 0, 0.75),
      0 0 0 2px var(--edge),
      inset 0 0 0 1px color-mix(in srgb, var(--neu) 45%, transparent);
  }
}

/* =========================================================================
   THE BLUE GLOW ON THE BIG TITLES
   Only the section headlines — the one-per-screen ones a presenter reads out
   loud. Small print, card titles and body copy stay plain, because a glow on
   everything is a glow on nothing.

   It is layered: a tight core that thickens the letterform, then two wider
   blooms. Colour comes from the brand blue rather than plain white, so the
   headline sits in the same light as the disc in the bar and the backlight
   behind the films.
   ========================================================================= */
.slide__title {
  text-shadow:
    0 0 1px color-mix(in srgb, var(--blue) 60%, transparent),
    0 0 12px color-mix(in srgb, var(--blue) 55%, transparent),
    0 0 34px color-mix(in srgb, var(--blue) 40%, transparent),
    0 0 72px color-mix(in srgb, var(--blue) 24%, transparent);
}

/* The hero is the biggest one on the site and sits over moving pictures, so
   it carries a little more, plus a dark base so it stays legible when a pale
   film slides underneath it. */
.slide__title--hero {
  text-shadow:
    0 2px 18px rgba(4, 10, 26, 0.55),
    0 0 2px color-mix(in srgb, var(--blue) 70%, transparent),
    0 0 16px color-mix(in srgb, var(--blue) 68%, transparent),
    0 0 44px color-mix(in srgb, var(--blue) 48%, transparent),
    0 0 96px color-mix(in srgb, var(--blue) 30%, transparent);
}

/* ── THE BUTTON THAT FOLLOWS THE RING ──
   Under "How It Works". Two lines: the chapter it is offering, and that
   chapter's own one-liner underneath, so the button says what you get rather
   than "Learn more". It changes as the ring turns. */
.howmore {
  position: relative; z-index: 3; align-self: center;
  display: inline-grid; grid-template-columns: 1fr auto;
  align-items: center; gap: 0 0.9rem;
  margin-top: 1.2rem; padding: 0.7rem 1.4rem;
  border-radius: 999px; text-decoration: none;
  background: var(--white); color: var(--blue);
  box-shadow: 0 16px 34px -16px rgba(0,0,0,0.45);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
  max-width: min(26rem, 92vw);
}
.howmore:hover { transform: translateY(-2px); box-shadow: 0 22px 40px -16px rgba(0,0,0,0.55); }
.howmore b {
  grid-column: 1; font: 800 1rem 'Inter', sans-serif; line-height: 1.2;
}
.howmore em {
  grid-column: 1; font-style: normal;
  font: 600 0.78rem 'Inter', sans-serif; line-height: 1.3;
  color: color-mix(in srgb, var(--blue) 72%, var(--black));
  /* one line: a chapter with a long description must not make the button grow
     to two different heights as the ring turns */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.howmore__go { grid-column: 2; grid-row: 1 / span 2; font-size: 1.2rem; font-weight: 800; }

@media (max-width: 820px) {
  .howmore { padding: 0.6rem 1.1rem; }
  .howmore b { font-size: 0.92rem; }
  .howmore em { font-size: 0.72rem; }
}

/* THE HEADING WAS UNDER THE SCRIM. That is the whole answer, and it took
   three goes to find because I kept measuring the text instead of the paint
   order. Inside the pinned stage: the film is z-index 0, the scrim is 1, the
   three stages are 2 — and `.howhead` had no position and no z-index at all,
   so it was the one thing in the section painting UNDERNEATH the veil. White
   letters under a 40% wash read grey; and when the wash was strengthened to
   90% to give the heading a darker backing, it went nearly black instead.
   Everything else in here was already above it, which is why only the heading
   ever looked wrong. */
.slide--teach .howhead { position: relative; z-index: 2; }

/* SECTION 2's HEADING IS NOT DIM — IT IS ON THE WRONG BACKGROUND.
   Every heading on the site is white, 700, the same size, with the same blue
   bloom. This one measured identical to the others and still read grey, and
   the reason is what is behind it: the scrim's dark band had faded to 40% by
   22% of the section, and the heading starts at 19.6%. Every other heading on
   the site sits on near-black; this one was sitting on a lit patch of film.

   The first attempt at this put a heavy dark shadow behind the letters, which
   made it worse — a dark halo tight around white glyphs smothers the blue
   bloom and reads muddier still. The heading keeps the ordinary treatment, the
   same as Sovereign and How It Works; it is the BACKING that was fixed, in
   .teach__scrim below. */
.slide--teach .orbit__hint { color: var(--white); opacity: 0.92; }

/* On a white section the same glow reads as a smudge — dark text does not
   emit light. Keep the colour, drop the wide blooms, and let it read as a
   faint blue halo instead. */
.slide--light .slide__title,
.overtitle--dark {
  text-shadow:
    0 0 1px color-mix(in srgb, var(--blue) 22%, transparent),
    0 0 18px color-mix(in srgb, var(--blue) 22%, transparent),
    0 0 40px color-mix(in srgb, var(--blue) 12%, transparent);
}

/* The torch effect punches a hole through the headline to show the pictures
   behind it. A glow drawn round a transparent letter is just a blue blur
   floating in the hole, so it goes while the hole is open. */
.herotitle.is-lit, .overtitle.is-lit, .slide__title.is-lit { text-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .slide__title, .slide__title--hero { transition: none; }
}

/* =========================================================================
   THE LIST BESIDE THE BALL
   The ball answers "how much is there and how does it connect". It cannot
   answer "what is it called" — a dot has no room for a title. So the same
   set is written out next to it, following whatever the picker has selected,
   and it scrolls, because one chapter can hold more than a column shows.
   ========================================================================= */
.gstage__body {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: 1fr minmax(260px, 340px); gap: 0.8rem;
  padding: 0 0.8rem;
}
.gstage__body .gstage__view { padding: 0; }

.glist {
  display: flex; flex-direction: column; min-height: 0;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 16px; overflow: hidden;
}
.glist__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem;
  padding: 0.7rem 0.85rem; border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  flex: none;
}
.glist__head b { color: var(--white); font-size: 0.86rem; line-height: 1.3; }
.glist__head span {
  flex: none; font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--white); opacity: 0.5;
}

.glist__items { list-style: none; margin: 0; padding: 0.3rem; overflow-y: auto; flex: 1; min-height: 0; }
.glist__items::-webkit-scrollbar { width: 8px; }
.glist__items::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.16); border-radius: 99px; }

.glist__item {
  display: flex; align-items: flex-start; gap: 0.55rem;
  padding: 0.5rem 0.55rem; border-radius: 11px;
  text-decoration: none; color: var(--white);
  transition: background 0.16s ease, transform 0.2s cubic-bezier(0.2, 1.35, 0.35, 1);
}
.glist__item:hover, .glist__item:focus-visible {
  background: rgba(255, 255, 255, 0.09); transform: translateX(2px);
}

/* one pip per chapter — a thing shared between two chapters shows two */
.glist__pips { display: flex; flex: none; gap: 2px; padding-top: 0.28rem; }
.glist__pips i {
  width: 7px; height: 7px; border-radius: 50%; display: block;
  box-shadow: 0 0 7px -1px currentColor;
}

.glist__txt { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.glist__txt b { font-size: 0.8rem; font-weight: 700; line-height: 1.35; }
.glist__txt em {
  font-style: normal; font-size: 0.68rem; line-height: 1.35;
  color: var(--white); opacity: 0.5;
}

.glist__now {
  flex: none; margin-left: auto; align-self: center;
  font-size: 0.58rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase;
  color: #0a2a18; background: #3ddc97; border-radius: 999px; padding: 0.12rem 0.4rem;
}
.glist__empty { padding: 1.2rem 0.9rem; font-size: 0.78rem; color: var(--white); opacity: 0.45; line-height: 1.5; }

/* the dot the pointer is currently over in the list */
.ngnode.is-hover .ngdot__hot { opacity: 1; }
.ngnode.is-hover .ngdot__glow { transform-box: fill-box; transform-origin: center; transform: scale(1.5); }

/* On a narrow screen the list goes underneath and takes a third of the
   height — the ball still has to be big enough to be worth turning. */
@media (max-width: 860px) {
  .gstage__body { grid-template-columns: 1fr; grid-template-rows: 1fr minmax(120px, 34%); }
}
@media (prefers-reduced-motion: reduce) {
  .glist__item { transition: none; }
}

/* THE STANDBY COPY.
   neuon.site exists for the days the office hosting neuon.ai has no internet.
   Somebody who arrives there should know within a second that it is the
   standby and where the real one lives — so this sits above the footer on
   every page, quiet but unmissable, and it is the only visible difference
   between the two sites. */
.standby {
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:0.5rem; padding:0.7rem 1.2rem; text-align:center;
  background:var(--black); color:var(--white); font-size:0.85rem;
}
.standby span { opacity:0.6; }
.standby a {
  color:var(--white); font-weight:800; text-decoration:none;
  border-bottom:2px solid color-mix(in srgb, var(--blue) 80%, transparent);
}
.standby a:hover { border-bottom-color:var(--white); }

/* THE CALL TO ACTION ON EVERY SECTION.
   One row, same shape everywhere, so a visitor learns once where the next
   step lives and then finds it on all eight. Inherits the section's own
   colours rather than carrying its own, because a blue button on the blue
   slide and a blue button on the white one are the same instruction. */
.ctarow {
  display:flex; align-items:center; gap:0.9rem; flex-wrap:wrap;
  margin-top:1.5rem; position:relative; z-index:3;
}
.ctarow__note { font-size:0.85rem; opacity:0.62; }
.btn.cta {
  display:inline-block; text-decoration:none;
  background:var(--blue); color:var(--white); border-color:var(--blue);
}
.btn.cta:hover { background:var(--blue-deep); border-color:var(--blue-deep); }
.slide--blue .btn.cta { background:var(--white); color:var(--blue); border-color:var(--white); }
.slide--blue .btn.cta:hover { background:var(--blue-pale); }
.slide--dark .btn.cta { background:var(--blue); color:var(--white); border-color:var(--blue); }
/* Section 1 carries no call-to-action row and no "See it working" any more —
   the chapter pill and its arrows are the only controls down there now. */

/* =========================================================================
   SECTION 1 — THE BOY AND THE BALL
   Two layers, one number. `--hp` runs 0 to 1 across the section's extra
   height and hero.js is the only thing that writes it.
   ========================================================================= */

/* The section is taller than the screen; that surplus IS the scroll the
   movement is spent over. `overflow: clip` and not `hidden`, because hidden
   creates a scroll container and a scroll container breaks the sticky stage
   inside it — the stage would simply never stick. */
.deck-page .slide--hero {
  /* 300vh, not 230. The extra 70 is ALL pause: hero.js's RUN was dropped from
     0.66 to 0.43 at the same time, which keeps the flight itself spending the
     same 86vh of scroll it always did. Raising the height without dropping RUN
     would have made the ball fly further per turn of the wheel, which is the
     opposite of what was asked. The two numbers only make sense together —
     change one and the other has to move. */
  min-height: 300vh;
  padding: 0;
  overflow: clip;
  display: block;
  scroll-snap-align: start;
}
.hero__pin {
  position: sticky; top: 0;
  height: 100vh; width: 100%;
  display: flex; flex-direction: column; justify-content: center;
  padding: calc(var(--nav-disc) + 1.6rem) clamp(1.6rem,6vw,6rem) 3rem;
  overflow: hidden;                    /* the reel still needs clipping */
}

/* The plate. It drifts left as the ball comes in — a small counter-move, so
   the ball reads as being PULLED across rather than the camera panning. */
.slide--hero .hero__bg {
  background-image: url('/assets/video/hero-kid-noglobe.jpg');
  /* THE PLATE MUST NEVER STOP COVERING.
     It drifts 2.5% left as the ball comes in. The first version also scaled
     it back down to 1.0 by the end — so at the end of the scroll it was
     exactly viewport-wide AND shifted left, which left a 32px strip of white
     page down the right-hand edge. The scale now bottoms out at 1.06, which
     is 76px of slack against a 32px drift: always more overhang than travel. */
  transform: translate3d(calc(var(--hp,0) * -2.5%), 0, 0) scale(calc(1.10 - var(--hp,0) * 0.04));
  transform-origin: 30% 55%;
  transition: transform 0.08s linear;
}
@media (max-width:820px) {
  .slide--hero .hero__bg { background-image: url('/assets/video/hero-kid-noglobe-sm.jpg'); }
}

/* THE BALL.
   Lands dead centre and full size — on the boy's eyeline, which is why `top`
   is 52% and not 50%.

   WHERE IT STARTS is set by the two offsets below, and it is a decision, not
   a leftover. It used to begin at 46vw out, which put more than half of it
   past the right-hand edge: the first thing anybody saw was a piece of
   something, and there was nothing to tell them a whole object was on its way
   in. It now starts high and to the right but FULLY on the screen — about 83%
   across and 38% down — so the thing that travels is visible from the first
   frame, and what the scroll does is bring it to the middle rather than
   introduce it. Change these two numbers to move the start; the landing is
   `top`/`left` and is not affected. */
.hero__ball {
  position: absolute; z-index: 1;
  top: 52%; left: 50%;
  width: clamp(19rem, 42vw, 40rem); aspect-ratio: 1;
  pointer-events: none;
  transform:
    translate3d(
      calc(-50% + (1 - var(--hp,0)) * 33vw),
      calc(-50% - (1 - var(--hp,0)) * 14vh),
      0)
    scale(calc(0.52 + var(--hp,0) * 0.48));
  opacity: calc(0.35 + var(--hp,0) * 0.65);
  transition: transform 0.08s linear, opacity 0.2s linear;
}
/* once it has landed it can be touched — not before, or it would swallow
   clicks on the reel while flying past */
.slide--hero.is-landed .hero__ball { pointer-events: auto; }
.hero__ballin { width: 100%; height: 100%; cursor: grab; }
.hero__ball.is-turning .hero__ballin { cursor: grabbing; }
.hero__ball .netgraph { width: 100%; height: 100%; }

/* Hovering halts it, as asked. The component's own drift is a CSS animation
   on the shell and pings; pausing them is what "stops moving" means to an eye
   — and the ball brightens slightly so it is obvious it answered. */
.hero__ball.is-held .netgraph__shell,
.hero__ball.is-held .netgraph__ping,
.hero__ball.is-held .netgraph__ping--2 { animation-play-state: paused; }
.hero__ball.is-held { filter: brightness(1.12) saturate(1.1); }

/* THE HEADLINE AT THE TOP, AND THE REEL UNDER IT — IN THAT ORDER, IN FLOW.
   The headline was pinned to the top and the reel was pinned to the middle,
   which meant nothing stopped them from meeting: at 1280x800 the first row of
   cards ran straight through "YOUR WORLD, UNDERSTOOD BY AI." Two absolutely
   positioned things cannot be made to avoid each other by choosing better
   numbers — the numbers are right until somebody opens a shorter window.

   So both come back into the flow and the pinned stage stacks them from the
   top. The reel is EARLIER in the markup than the headline (it has to be: the
   film cards are generated above it), which is what `order` is for. */
.hero__pin { justify-content: flex-start; }
.slide--hero .herokick,
.slide--hero .herotitle {
  position: static; transform: none;
  width: min(46rem, 90vw); margin-left: auto; margin-right: auto;
}
.slide--hero .herokick { order: -2; margin-top: 0.5rem; margin-bottom: 0.2rem; }
.slide--hero .herotitle { order: -1; margin-top: 0; margin-bottom: 0; }
/* and the reel takes what is left, under them.
   It has to break out of the stage's padding to keep running off both edges
   of the screen — in flow it would sit inside the padding and the cards would
   stop short of the edge, which loses the sense of a strip still going. */
.slide--hero .reel {
  position: static; transform: none; margin-top: clamp(0.8rem, 3vh, 2.2rem);
  width: 100vw; margin-inline: calc(50% - 50vw);
  flex: none;                 /* never squashed: it clips a row when it is */
}

/* A SHORT WINDOW. The cards are sized from viewport height so they come down
   on their own, but the headline is sized from viewport WIDTH and does not —
   so on a wide, short window the two rows no longer fitted underneath it and
   the second one was cut in half. The headline gives up the difference. */
@media (max-height: 780px) {
  .slide--hero .herotitle { font-size: clamp(1.6rem, 4.2vw, 2.6rem); }
  .slide--hero .reel { margin-top: 0.6rem; }
  .slide--hero .reel.reel--desk { padding: 0.8rem 0; }
}

/* The words step back as the ball arrives — one thing at a time. */
.slide--hero .herokick,
.slide--hero .herotitle,
.slide--hero .reel,
.slide--hero .herowatch { opacity: var(--hp-text, 1); transition: opacity 0.2s linear; }
.slide--hero .ctarow { opacity: var(--hp-text, 1); }

/* Anyone who asked for less movement gets the finished picture, no travel. */
.slide--hero.is-still { min-height: 100vh; }
.slide--hero.is-still .hero__ball { transition: none; }

@media (max-width:820px) {
  /* ONE SCREEN. This used to be 190vh — the travel the ball's flight was spent
     over. A phone does not fly the ball any more, so there is nothing to spend
     it on and it was just a wall of scrolling before anything could be read.
     The ball's own size and place are set further down, with everything else
     that hangs off it. */
  .deck-page .slide--hero { min-height: 100vh; }
}

/* ── Section 1, revised: Dr KC's footage, scrubbed not played ──
   The plate is a <video> now. It is never played: hero.js sets currentTime
   from the scroll position, so the boy moves exactly as far as somebody has
   scrolled and stops dead when they stop. That is the whole point — a picture
   that moves on its own has to be stopped and explained; this one answers the
   hand already on the mouse. */
.slide--hero video.hero__bg {
  width: 100%; height: 100%; object-fit: cover;
  background: #08131f;
}

/* ── the reel keeps tracking ──
   It was stopped for a round and Dr KC asked for it back: the drifting row is
   what tells a visitor at a glance that there is a lot to look at. What he
   did not want was the BACKGROUND playing on its own, and that is now scrubbed
   by scroll instead. This one still pauses while a film is open. */

/* ── the call to action sits centred on the sections that are centred ── */
.slide#sovereign .ctarow,
.slide#how-it-works .ctarow,
.slide#commitment .ctarow,
.slide#sdg .ctarow,
.slide#news .ctarow { justify-content: center; }

/* Our Commitment: at the BOTTOM, in the middle.
   The button was rendering ABOVE the heading even though it is last in the
   markup, because this section's children carry their own flex `order` — so
   position in the file decides nothing here. `order` is the only thing that
   does, and 99 puts it after everything. A call to action belongs after the
   things it is asking you to believe, not before them. */
.slide#commitment .ctarow {
  order: 99;
  width: 100%;
  margin-top: 1.6rem;
  justify-content: center;
}

/* the NEU the ball is currently showing, at the end of the scroll */
.heroneu {
  position: absolute; left: 50%; bottom: 12%;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.45rem 1.1rem; border-radius: 999px;
  background: rgba(8, 19, 31, 0.72); backdrop-filter: blur(6px);
  border: 1.5px solid rgba(255, 255, 255, 0.18);
  font: 800 0.9rem 'Inter', sans-serif; color: var(--white);
  opacity: 0; transition: opacity 0.25s ease;
  pointer-events: none; white-space: nowrap; z-index: 2;
}
.slide--hero.is-landed .heroneu { opacity: 1; }
.heroneu i { width: 0.6rem; height: 0.6rem; border-radius: 50%; background: var(--c, #8ec5ff); }
.heroneu em { font-style: normal; font-weight: 600; opacity: 0.6; font-size: 0.8rem; }

/* how long a film runs, on its card. Top-right so it never fights the title
   along the bottom, and always legible over whatever the still happens to be. */
.rcard__mins {
  position: absolute; top: 0.5rem; right: 0.5rem; z-index: 2;
  font: 800 0.7rem 'Inter', sans-serif; letter-spacing: 0.02em;
  padding: 0.15rem 0.45rem; border-radius: 6px;
  background: rgba(8, 19, 31, 0.78); color: var(--white);
}

/* ── the chapter name, and what it opens ── */
.heroneu { cursor: pointer; border: 1.5px solid rgba(255,255,255,0.18); }
.heroneu[hidden] { display: none; }
.slide--hero.is-landed .heroneu { pointer-events: auto; }
.heroneu:hover { background: rgba(8,19,31,0.9); border-color: rgba(255,255,255,0.4); }
.heroneu b { font-weight: 800; }
.heroneu::after { content: '▸'; opacity: 0.5; margin-left: 0.15rem; }

/* The panel is centred in the space BELOW the header, not in the viewport.
   The NEUON mark in the header is fixed and hangs about 8.5rem down the middle
   of the screen — dead centre of anything this size — so it was landing on the
   ball. Padding here rather than inside the panel, because the scrim is
   positioned against the padding box and still covers the whole screen. */
.neufan {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  padding: 9.5rem 0 1rem;
}
.neufan[hidden] { display: none; }
.neufan__scrim { position: absolute; inset: 0; background: rgba(4,10,20,0.82); backdrop-filter: blur(4px); }
.neufan__panel {
  position: relative; width: min(64rem, calc(100vw - 2rem)); max-height: 100%;
  background: linear-gradient(180deg, #0b1a2c, #071119);
  border: 1px solid rgba(255,255,255,0.12); border-radius: 22px;
  padding: 1.4rem 1.2rem; overflow: hidden;
  display: flex; flex-direction: column;
}
.neufan__x {
  position: absolute; top: 1rem; right: 1rem; z-index: 70;
  width: 2.2rem; height: 2.2rem; border-radius: 50%; border: 0;
  background: rgba(255,255,255,0.12); color: var(--white); font-size: 1.2rem; cursor: pointer;
}
.neufan__x:hover { background: var(--blue); }

/* the ball and the chapter it is showing, with a way either side of it */
.neufan__head { display: flex; align-items: center; justify-content: center; gap: 1rem; }
.neufan__who { display: grid; justify-items: center; gap: 0.15rem; }
.neufan__core {
  width: clamp(5rem, 9vw, 7rem); aspect-ratio: 1;
  pointer-events: none;                 /* it is the badge for the list, not a control */
}
.neufan__core .netgraph { width: 100%; height: 100%; }
/* on a laptop screen the badge gives up its height to the list — the films
   are what somebody opened this for */
@media (max-height: 820px) { .neufan__core { width: 4.5rem; } }
/* the list takes whatever height is left and scrolls inside itself, so a
   chapter with twenty films never pushes the panel off the screen */
.neufan__stage { position: relative; margin-top: 1rem; overflow: auto; flex: 1 1 auto; min-height: 0; }
.neufan__head, .neufan__hint { flex: none; }

/* next and previous chapter, without closing and opening again */
.neufan__step {
  flex: none; width: 2.6rem; height: 2.6rem; border-radius: 50%; cursor: pointer;
  border: 1.5px solid rgba(255,255,255,0.2); background: rgba(255,255,255,0.08);
  color: var(--white); font-size: 1.2rem; line-height: 1; z-index: 60;
  display: grid; place-items: center;
  transition: background 0.16s ease, border-color 0.16s ease, transform 0.12s ease;
}
.neufan__step:hover { background: var(--blue); border-color: var(--blue); transform: scale(1.08); }
.neufan__step:active { transform: scale(0.95); }

/* the chapter, named under its own ball */
.neufan__name {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  color: var(--white); text-align: center;
}
.neufan__dot {
  width: 0.7rem; height: 0.7rem; border-radius: 50%; background: var(--c, #8ec5ff); flex: none;
}
.neufan__name b { font-size: clamp(1.15rem, 2.4vw, 1.5rem); font-weight: 800; }
.neufan__role { font-style: normal; font-size: 0.85rem; color: rgba(255,255,255,0.6); }
.neufan__hint { text-align: center; font-size: 0.8rem; color: rgba(255,255,255,0.5); margin-top: 0.7rem; }

/* ── the films, the way a video list looks everywhere else ──
   Still, running time in the corner of it, title underneath. Nobody has to be
   told how to read this one, which is the entire point of borrowing it. */
.ytgrid {
  display: grid; gap: 1.1rem 1rem; padding: 0.2rem 0.2rem 0.4rem;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
}
.ytcard {
  display: grid; gap: 0.55rem; align-content: start;
  border: 0; padding: 0; background: none; cursor: pointer; text-align: left;
}
.ytcard__thumb {
  position: relative; display: block; aspect-ratio: 16/9; overflow: hidden;
  border-radius: 12px; background: #0b1a2c;
  box-shadow: 0 14px 30px -14px rgba(0,0,0,0.8);
  transition: transform 0.16s ease, box-shadow 0.16s ease;
}
.ytcard__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ytcard:hover .ytcard__thumb { transform: translateY(-3px); box-shadow: 0 20px 36px -14px rgba(0,0,0,0.9); }
.ytcard:focus-visible { outline: none; }
.ytcard:focus-visible .ytcard__thumb { outline: 3px solid var(--c, #8ec5ff); outline-offset: 3px; }

/* how long it runs, bottom-right of the still */
.ytcard__dur {
  position: absolute; right: 0.4rem; bottom: 0.4rem; z-index: 2;
  font: 800 0.68rem 'Inter', sans-serif; letter-spacing: 0.02em;
  padding: 0.12rem 0.34rem; border-radius: 5px;
  background: rgba(0,0,0,0.78); color: #fff;
}
/* the play triangle, only once a pointer is on the card — a still with a
   permanent button over the middle of it hides the thing being chosen */
.ytcard__play {
  position: absolute; inset: 0; z-index: 1; display: grid; place-items: center;
  opacity: 0; transition: opacity 0.16s ease; background: rgba(4,10,20,0.28);
}
.ytcard__play::before {
  content: ''; width: 0; height: 0;
  border-left: 1.1rem solid #fff;
  border-top: 0.68rem solid transparent; border-bottom: 0.68rem solid transparent;
  filter: drop-shadow(0 2px 6px rgba(0,0,0,0.6));
}
.ytcard:hover .ytcard__play, .ytcard:focus-visible .ytcard__play { opacity: 1; }

.ytcard__meta { display: grid; gap: 0.15rem; }
.ytcard__meta strong {
  font: 700 0.86rem/1.35 'Inter', sans-serif; color: var(--white);
  /* two lines, then an ellipsis — a title is a label here, not the article */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ytcard__meta em { font-style: normal; font-size: 0.74rem; color: var(--c, #8ec5ff); font-weight: 700; }

@media (max-width: 700px) {
  /* the mark is smaller on a phone, so less room has to be left for it */
  .neufan { padding-top: 7.25rem; }
  .neufan__core { width: min(4.5rem, 18vw); }
  .neufan__step { width: 2.2rem; height: 2.2rem; }
  .ytgrid { grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: 0.9rem 0.7rem; }
  .ytcard__meta strong { font-size: 0.78rem; }
}

/* the film cards on the ring */
.fcard {
  display: block; width: clamp(8rem, 12vw, 11rem); aspect-ratio: 3/4;
  border: 0; padding: 0; cursor: pointer; border-radius: 14px; overflow: hidden;
  position: relative; background: #0b1a2c;
  box-shadow: 0 18px 40px -18px rgba(0,0,0,0.8);
}
.fcard img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.fcard__tag {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 1.6rem 0.6rem 0.55rem; text-align: left;
  font: 700 0.72rem 'Inter', sans-serif; color: var(--white); line-height: 1.3;
  background: linear-gradient(transparent, rgba(4,10,20,0.92));
}
.fcard__mins {
  position: absolute; top: 0.4rem; right: 0.4rem; z-index: 2;
  font: 800 0.66rem 'Inter', sans-serif; padding: 0.12rem 0.4rem; border-radius: 5px;
  background: rgba(8,19,31,0.8); color: var(--white);
}
.neufan__none { color: rgba(255,255,255,0.6); text-align: center; padding: 4rem 1rem; }

/* ── SIGN UP TO HEAR MORE ──
   The shape Dr KC marked up: one pill, the field on the left, the button on
   the right, joined rather than sitting apart. Under the chapter row so it is
   the last thing on the section, and it fades with the rest of the words as
   the ball takes the stage — a form floating over a landed ball would be
   asking for two things at once. */
.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* AT THE END OF THE SCROLL, NOT THE START.
   Dr KC's note, and it is about the order a pitch happens in: he talks the
   room through the chapters first and only then asks for the address. A form
   sitting there before anybody has heard anything is asking for a favour from
   a stranger. So it belongs to the landed state — the same moment the chapter
   row appears — and it is not on the screen before that.

   It also means the form no longer competes for room with the headline and
   the reel, which is why the headline is back to full size: at the start of
   the scroll this is not in the layout at all. */
.signup {
  position: absolute; left: 50%; bottom: 6.5%; transform: translateX(-50%);
  z-index: 5; display: flex; align-items: stretch; flex-wrap: wrap;
  justify-content: center; gap: 0;
  /* 100%, not 90vw: the stage has padding, and a width measured against the
     VIEWPORT overflowed the content box and sat off-centre on a phone. */
  width: min(30rem, 100%); max-width: calc(100vw - 2rem);
  background: rgba(255,255,255,0.96); backdrop-filter: blur(6px);
  border-radius: 12px; padding: 0.34rem;
  box-shadow: 0 20px 44px -18px rgba(0,0,0,0.7);
  /* hidden to the keyboard too, or tab lands in a form nobody can see */
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 0.28s ease, visibility 0s linear 0.28s;
}
.slide--hero.is-landed .signup {
  opacity: 1; visibility: visible; pointer-events: auto;
  transition: opacity 0.28s ease, visibility 0s;
}

.signup__field { flex: 1 1 10rem; display: flex; min-width: 0; }
.signup__field input {
  width: 100%; border: 0; background: none; outline: none;
  padding: 0.6rem 0.8rem; min-width: 0;
  font: 500 0.95rem 'Inter', sans-serif; color: #0b1a2c;
}
.signup__field input::placeholder { color: rgba(11,26,44,0.5); }
.signup__field input:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; border-radius: 8px; }

.signup__go {
  flex: none; border: 0; cursor: pointer; border-radius: 9px;
  padding: 0.6rem 1.1rem; white-space: nowrap;
  background: var(--blue); color: var(--white);
  font: 800 0.9rem 'Inter', sans-serif;
  transition: background 0.16s ease, transform 0.12s ease;
}
.signup__go:hover { background: var(--blue-deep); }
.signup__go:active { transform: scale(0.97); }
.signup__go[disabled] { opacity: 0.6; cursor: default; }

/* the answer takes the whole width under the pill, so the row never jumps */
.signup__say {
  flex: 1 0 100%; text-align: center; margin: 0.35rem 0 0.1rem;
  font: 600 0.78rem 'Inter', sans-serif; color: #0b1a2c;
}
.signup__say:empty { display: none; }
.signup__say.is-bad { color: #b3261e; }
/* it has done its job — the field and the button go, the thank-you stays */
.signup.is-done .signup__field, .signup.is-done .signup__go { display: none; }
.signup.is-done .signup__say { margin: 0.35rem 0; }

@media (max-width: 820px) {
  /* lower than on a desktop: the chapter row sits at 6rem from the foot here,
     and at 6.5% the form was 5px into it */
  .signup { width: min(26rem, 100%); bottom: 2.4%; }
  .signup__go { padding: 0.6rem 0.8rem; font-size: 0.82rem; }
  /* a narrower basis, or the field claims 10rem and pushes the button onto a
     second line — one pill, one row, as marked up */
  .signup__field { flex-basis: 6rem; }
}

/* ── skipping through the chapters by hand ──
   The ball moves on by itself every couple of seconds. On a stage that is
   sometimes too slow and sometimes too fast, so there are arrows: press one
   and it goes straight to the next chapter and restarts the clock. */
/* Up off the floor of the screen. At 12% it sat right on the bottom edge of
   the pinned stage and was the first thing clipped on a short window. */
.heronav {
  position: absolute; left: 50%; bottom: 19%;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 0.5rem; z-index: 3;
  opacity: 0; transition: opacity 0.25s ease; pointer-events: none;
}
.slide--hero.is-landed .heronav { opacity: 1; pointer-events: auto; }
.heronav .heroneu { position: static; transform: none; opacity: 1; }
.heroarrow {
  width: 2.2rem; height: 2.2rem; flex: none; border-radius: 50%; cursor: pointer;
  border: 1.5px solid rgba(255,255,255,0.2); background: rgba(8,19,31,0.72);
  color: var(--white); font-size: 1rem; line-height: 1;
  backdrop-filter: blur(6px);
  display: grid; place-items: center;
  transition: background 0.16s ease, border-color 0.16s ease, transform 0.12s ease;
}
.heroarrow:hover { background: var(--blue); border-color: var(--blue); transform: scale(1.08); }
.heroarrow:active { transform: scale(0.95); }

/* the burst of charges before the ball hands over to the next chapter —
   the same signal Section 2 uses, so the two read as one machine */
.hero__ball.is-zapping .netgraph__shell { animation-duration: 0.5s; }
.hero__ball.is-zapping { filter: brightness(1.18) saturate(1.15); }

/* An aimed charge carries its chapter's colour, set inline by netgraph.js, so
   the stroke here must not overrule it — `is-charged` alone paints white. */
.netgraph__links line.is-charged.is-aimed { stroke-width: 1.6; }

/* On a phone "See it working" leaves the right-hand corner and centres itself
   at the foot of the section — straight underneath the call to action and the
   chapter nav, which both sit centred too. On a wide screen they miss each
   other by 165px; here they overlapped by 24. Both are lifted clear. */
@media (max-width: 820px) {
  /* JUST THE NAME.
     "NEUTalents The people chapter" is a comfortable phrase on a wide screen
     and half the width of a phone. The role is dropped here so the pill stays
     a pill — it is still read out to screen readers through the button's
     aria-label, so nothing is lost, only hidden. */
  .heroneu em { display: none; }

  /* nothing else is down here now, so the pill sits where the eye already is */
  .heronav { bottom: 6rem; }
}

/* ── the chapter, hung off the ball ──
   Dr KC's sketch: the name floating by the lit dot, and one of that chapter's
   films directly under it. It rides with the ball, so it grows and travels
   with it, and it freezes when the ball does. */
/* THE FILMS, ON THE BALL.
   A window hangs off each side, so the ball is flanked rather than lopsided.
   Positioned against the ball itself, which means they travel with it and land
   where it lands. The chapter is named once, at the foot — it used to be named
   here as well, which put a second copy of the same word directly under the
   NEUON mark in the header. */

/* the two windows */
.herofilm {
  position: absolute; z-index: 4; top: 26%;
  /* Big enough to actually watch a still, as asked — about a quarter of the
     window each, which is what fits either side of the ball at 1280 without
     the two of them touching it. */
  width: clamp(11rem, 25vw, 22rem); aspect-ratio: 16/10;
  border-radius: 16px; border: 1.5px solid rgba(255,255,255,0.16);
  background: #0b1a2c; padding: 0; overflow: hidden; cursor: pointer;
  box-shadow: 0 22px 44px -18px rgba(0,0,0,0.85);
  opacity: 0; pointer-events: none;
  transition: opacity 0.28s ease, transform 0.18s ease, border-color 0.18s ease;
}
.herofilm[hidden] { display: none; }
.slide--hero.is-landed .herofilm { opacity: 1; pointer-events: auto; }
/* Clear of the ball's LIT CIRCLE, which is smaller than its square box —
   at 82% the windows were sitting on the outermost dots. */
.herofilm--l { right: 87%; }
.herofilm--r { left: 87%; }
.herofilm:hover { transform: translateY(-3px); border-color: var(--c, #8ec5ff); }
.herofilm img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.herofilm__tag {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 1.8rem 0.7rem 0.6rem; text-align: left;
  font: 700 0.82rem 'Inter', sans-serif; color: var(--white); line-height: 1.3;
  background: linear-gradient(transparent, rgba(4,10,20,0.94));
}
.herofilm__more {
  position: absolute; top: 0.45rem; right: 0.45rem; z-index: 2;
  font: 800 0.68rem 'Inter', sans-serif; padding: 0.16rem 0.5rem; border-radius: 6px;
  background: rgba(8,19,31,0.82); color: var(--white);
}
.herofilm__more:empty { display: none; }

/* THE NAME ALONE, at the bottom.
   "NEUMotion First second-generation graduate (with Dr. Abel)" is a sentence,
   not a label — and the chapter is now named on the ball as well, so the row
   at the foot only has to say which one. */
.heroneu em { display: none; }

/* PAGING THROUGH THE REST OF THE CHAPTER.
   Two windows show two films, and most chapters have more than two. These step
   the pair on and back. They are for the phone, where there is no room to make
   the windows bigger AND show more of them — on a desktop the row at the foot
   already has arrows and a second pair beside them would just be a puzzle. */
.herofilmnav {
  position: absolute; z-index: 5; left: 50%; transform: translateX(-50%);
  top: 88%; display: none; gap: 0.8rem;
  opacity: 0; pointer-events: none; transition: opacity 0.28s ease;
}
.slide--hero.is-landed .herofilmnav { opacity: 1; pointer-events: auto; }
.herofilmnav[hidden] { display: none !important; }
.herofilmnav button {
  width: 2.4rem; height: 2.4rem; border-radius: 50%; cursor: pointer;
  border: 1.5px solid rgba(255,255,255,0.28); background: rgba(8,19,31,0.72);
  color: var(--white); font-size: 1rem; line-height: 1;
  backdrop-filter: blur(6px); display: grid; place-items: center;
}
.herofilmnav button:active { transform: scale(0.94); }

/* ── SECTION 1 ON A PHONE: ONE SCREEN, NO FLIGHT ──
   The ball flying in from the corner is worth a screen and a half of scroll
   on a laptop. On a phone it was a screen and a half before anything could be
   read, with the reel of films underneath as a second wall. So the section is
   one screen tall, hero.js marks it landed from the start, and what a phone
   gets is the finished arrangement Dr KC drew: headline, ball, two films with
   their arrows, the chapter row, the sign-up.

   Everything below is measured against the BALL, because on a phone the ball
   no longer moves — it is the fixed thing everything else can hang from. */
@media (max-width: 820px) {
  .slide--hero { min-height: 100vh; }
  /* the reel is the wall. Gone on a phone; the two windows on the ball are
     how films are reached here, and they page. */
  .reel--mob, .slide--hero .reel { display: none; }

  /* IN THE FLOW, under the headline. The third time today this is the answer:
     the ball's `top` is a percentage of viewport HEIGHT while its size is a
     percentage of viewport WIDTH, so on a shorter phone it rode up into the
     headline and no single percentage fixes both. In the flow it simply sits
     after the headline, whatever the headline turned out to be.
     The windows and their arrows stay hung off the ball and travel with it. */
  .slide--hero .hero__ball {
    /* relative, NOT static: the two windows and their arrows are positioned
       against the ball, and a static ball is not a containing block — they
       measured themselves against the whole pinned stage instead and landed
       hundreds of pixels down the page. */
    position: relative; transform: none; margin: 1.1rem auto 0;
    top: auto; left: auto; width: min(53vw, 13rem);
  }

  /* the two films, just under the ball */
  .herofilm { top: 106%; width: min(45vw, 11.5rem); }
  .herofilm--l { right: 51%; }
  .herofilm--r { left: 51%; }
  .herofilm__tag { font-size: 0.62rem; padding: 1rem 0.4rem 0.35rem; }
  /* and their arrows under those — 106% plus a window's own height */
  .herofilmnav { display: flex; top: 164%; }
}
