/* ============================================================================
   INSIGHT BAY, PHYSICS
   physics.css

   Third sister to space.css and mathematics.css. Parts A and B below are the
   SAME code as those files, deliberately: /space, /mathematics and /physics
   have to be one object in three subjects, not three designs that happen to
   share a logo. If you change a shared value, change it in all three, or the
   pages drift and a parent notices before you do.

   This file has three parts.

   PART A, BRAND BASE (mirrored, byte-for-byte, from /assets/css/styles.css).
            Present only so this page can be opened and reviewed on its own,
            with no other stylesheet loaded. If you would rather link the
            existing site stylesheet, delete PART A and add
            <link rel="stylesheet" href="/assets/css/styles.css"> before this
            file. Nothing below depends on PART A being local, it only
            consumes --ib-* custom properties, which either file provides.

   PART B, THE CINEMATIC PAGE KIT. Everything is namespaced .sx-*. Void
            panels, numbered chapters, tiles, the timeline, the stage switch,
            the FAQ and the final call to action. Shared with /space and
            /mathematics, which is why the prefix stays .sx-. It adds no new
            colours, no new radii, no new type family. Every value resolves
            back to an --ib-* token.

   PART C, THE PHYSICS LAYER, namespaced .px-*. Field-line voids, the
            cannonball hero, the scroll-driven equal-fall scene at Hadley,
            the eight-branch explorer, the syllabus map and the pendulum
            interactive. Nothing in PART C is used by the other two pages.

   Design rule that governs the whole page:
   ----------------------------------------
   The cinematic passages ("void" panels) are ALWAYS dark, in both light and
   dark mode, exactly as the site footer is already always dark. They are not
   a second theme. They are the existing dark surface, used at full height.
   Inside a void panel we re-point the --ib-* tokens to their dark values, so
   .ib-btn, .ib-eyebrow, .ib-card and every other brand component keeps working
   untouched. That is the whole trick, and it is why the page cannot drift.
   ========================================================================= */


/* ==========================================================================
   PART A, BRAND BASE (mirror of styles.css)
   ========================================================================== */

:root {
  --ib-bg: #F5F1EB;
  --ib-bg-soft: #FAF7F2;
  --ib-bg-deep: #EEE9DD;
  --ib-ink: #20201E;
  --ib-ink-soft: #4A4742;
  --ib-ink-muted: #6B655C;
  --ib-line: #E2DCCF;
  --ib-line-strong: #C9C0AE;
  --ib-accent: #C96442;
  --ib-accent-ink: #B2502F;
  --ib-accent-ink-hover: #A0482A;
  --ib-accent-hover: #B25535;
  --ib-accent-soft: #F3DDCF;
  --ib-gold: #B58A3A;
  --ib-success: #4F7A4A;
  --ib-shadow: 0 1px 2px rgba(32,32,30,.04), 0 0.5rem 1.5rem -0.5rem rgba(32,32,30,.12);
  --ib-shadow-lg: 0 0.25rem 0.75rem rgba(32,32,30,.06), 0 1.5rem 3rem -1rem rgba(32,32,30,.18);
  --ib-bg-hero-top: #FFFDF8;
  --ib-grid-line: rgba(32,32,30,.05);
  --ib-nav-bg: rgba(245,241,235,0.85);
  --ib-card-bg: #FFFFFF;
  --ib-footer-bg: #20201E;
  --ib-footer-text: #F5F1EB;
  --ib-footer-text-soft: rgba(245,241,235,.85);
  --ib-footer-text-faint: rgba(245,241,235,.55);
  --ib-footer-line: rgba(245,241,235,.12);
  --ib-emphasis-bg: #20201E;
  --ib-emphasis-text: #F5F1EB;
  --ib-emphasis-text-soft: rgba(245,241,235,.85);
  --ib-emphasis-text-faint: rgba(245,241,235,.6);
  --ib-emphasis-line: rgba(245,241,235,.15);
  --ib-radius-sm: 0.5rem;
  --ib-radius: 0.875rem;
  --ib-radius-lg: 1.375rem;
  --ib-font-serif: 'Inter','Helvetica Neue',Arial,system-ui,sans-serif;
  --ib-font-sans: 'Inter','Helvetica Neue',Arial,system-ui,sans-serif;
  --ib-font-mono: 'IBM Plex Mono',ui-monospace,'SFMono-Regular',Menlo,monospace;
  --ib-font-stamp: 'Inter','Helvetica Neue',Arial,system-ui,sans-serif;
  --ibe-out: cubic-bezier(.22,.61,.21,1);
  --ibe-pop: cubic-bezier(.3,1.25,.4,1);
  --ibe-spring: cubic-bezier(.34,1.45,.5,1);
  --ib-dur-1: .16s;
  --ib-dur-2: .3s;
  --ib-dur-3: .55s;
  --ib-field-line: #948871;
}

[data-theme="dark"] {
  --ib-bg: #1A1916;
  --ib-bg-soft: #1E1D1A;
  --ib-bg-deep: #232220;
  --ib-ink: #F2EFE8;
  --ib-ink-soft: #C9C4BB;
  --ib-ink-muted: #8E8A82;
  --ib-line: #343129;
  --ib-line-strong: #45413A;
  --ib-accent: #E8845E;
  --ib-accent-ink: #E8845E;
  --ib-accent-ink-hover: #F19770;
  --ib-accent-hover: #F19770;
  --ib-accent-soft: #3D2A20;
  --ib-gold: #D9B265;
  --ib-success: #7AAE73;
  --ib-shadow: 0 1px 2px rgba(0,0,0,.4), 0 0.5rem 1.5rem -0.5rem rgba(0,0,0,.55);
  --ib-shadow-lg: 0 0.25rem 0.75rem rgba(0,0,0,.45), 0 1.5rem 3rem -1rem rgba(0,0,0,.7);
  --ib-bg-hero-top: #1F1D1A;
  --ib-grid-line: rgba(242,239,232,.06);
  --ib-nav-bg: rgba(26,25,22,0.85);
  --ib-card-bg: #211F1C;
  --ib-footer-bg: #141311;
  --ib-footer-text: #F2EFE8;
  --ib-footer-text-soft: rgba(242,239,232,.85);
  --ib-footer-text-faint: rgba(242,239,232,.55);
  --ib-footer-line: rgba(242,239,232,.12);
  --ib-emphasis-bg: #232120;
  --ib-emphasis-text: #F2EFE8;
  --ib-emphasis-text-soft: rgba(242,239,232,.85);
  --ib-emphasis-text-faint: rgba(242,239,232,.6);
  --ib-emphasis-line: rgba(242,239,232,.1);
  --ib-field-line: #6F6960;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* Several components below set display:grid/flex, which would otherwise beat
   the UA rule for [hidden]. The tab explorer depends on this holding. */
[hidden] { display: none !important; }
body {
  margin: 0;
  background: var(--ib-bg);
  color: var(--ib-ink);
  font-family: var(--ib-font-sans);
  font-feature-settings: "ss01","cv11";
  line-height: 1.6;
  font-size: 1rem;
}
body, .ib-nav, .ib-mobile-menu, .ib-card, .ib-footer, input, textarea, select, button, a {
  transition: background-color .25s, color .2s, border-color .2s;
}
body h1, body h2, body h3, body h4, body h5 {
  font-family: var(--ib-font-sans);
  color: var(--ib-ink);
  letter-spacing: -.015em;
  line-height: 1.15;
  font-weight: 700;
  text-transform: none;
  margin: 0;
}
body h1 { font-size: clamp(2.4rem, 4.8vw, 3.8rem); font-weight: 800; letter-spacing: -.025em; }
body h2 { font-size: clamp(1.7rem, 3.2vw, 2.4rem); letter-spacing: -.02em; }
body h3 { font-size: clamp(1.15rem, 1.8vw, 1.35rem); }
h1, h2, h3, blockquote { overflow-wrap: break-word; }
p { margin: 0; }
a { color: var(--ib-accent-ink); text-decoration: none; }
a:hover { color: var(--ib-accent-hover); }
img, svg { max-width: 100%; }
ul { margin: 0; padding: 0; list-style: none; }

a:focus-visible, button:focus-visible, .ib-btn:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--ib-accent);
  outline-offset: 2px;
  border-radius: 0.25rem;
}

.ib-container { max-width: 73.75rem; margin-inline: auto; padding-inline: 1.25rem; min-width: 0; }
.ib-section { padding-block: 5rem; min-width: 0; }
.ib-band { max-width: 51.25rem; }

.ib-eyebrow {
  font-family: var(--ib-font-sans);
  font-size: .95rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ib-accent);
  font-weight: 700;
}

.ib-btn {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .85rem 1.4rem; border-radius: 62.4375rem;
  font-weight: 500; font-size: .95rem;
  transition: .18s; border: 1px solid transparent; cursor: pointer;
  font-family: inherit; text-decoration: none;
}
.ib-btn-primary { background: var(--ib-ink); color: var(--ib-bg); }
.ib-btn-primary:hover { background: var(--ib-accent-ink); color: #fff; transform: translateY(-1px); }
.ib-btn-accent { background: var(--ib-accent-ink); color: #fff; }
.ib-btn-accent:hover { background: var(--ib-accent-ink-hover); color: #fff; transform: translateY(-1px); }
.ib-btn-ghost { background: transparent; color: var(--ib-ink); border-color: var(--ib-line-strong); }
.ib-btn-ghost:hover { background: var(--ib-bg-deep); color: var(--ib-ink); }

.ib-card {
  background: var(--ib-bg-soft);
  border: 1px solid var(--ib-line);
  border-radius: var(--ib-radius);
  padding: 1.75rem;
  transition: transform .25s, box-shadow .25s, border-color .25s;
}
.ib-card:hover { border-color: var(--ib-line-strong); box-shadow: var(--ib-shadow); transform: translateY(-2px); }

.ib-reveal { opacity: 0; transform: translateY(1.75rem); transition: opacity .8s, transform .8s cubic-bezier(.2,.7,.2,1); }
.ib-reveal.is-visible { opacity: 1; transform: translateY(0); }

/* --- Navigation (mirror) ------------------------------------------------- */
.ib-nav {
  position: sticky; top: 0; z-index: 50;
  background: var(--ib-nav-bg);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--ib-line);
}
.ib-nav-inner { display: flex; align-items: center; justify-content: space-between; height: 4.25rem; }
.ib-logo {
  font-family: var(--ib-font-sans); font-size: 1.3rem; font-weight: 700;
  color: var(--ib-ink); letter-spacing: -.02em;
  display: flex; align-items: center; gap: .5rem;
}
.ib-logo:hover { color: var(--ib-ink); }
.ib-logo-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.875rem; height: 1.875rem; background: var(--ib-accent); color: #fff;
  border-radius: 0.5rem; font-style: italic; font-weight: 700; font-size: 1.05rem;
}
.ib-nav-links { display: none; gap: 2rem; }
.ib-nav-links a { color: var(--ib-ink-soft); font-size: .92rem; font-weight: 500; position: relative; }
.ib-nav-links a:hover, .ib-nav-links a.active { color: var(--ib-ink); }
.ib-nav-links a.active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1.375rem;
  height: 2px; background: var(--ib-accent);
}
.ib-nav-actions { display: flex; align-items: center; gap: .75rem; }
.ib-theme-toggle, .ib-menu-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.375rem; height: 2.375rem; border-radius: 62.4375rem;
  border: 1px solid var(--ib-line-strong); background: transparent;
  color: var(--ib-ink); cursor: pointer; padding: 0;
}
.ib-theme-toggle:hover, .ib-menu-toggle:hover { background: var(--ib-bg-deep); }
.ib-theme-toggle__moon { display: none; }
[data-theme="dark"] .ib-theme-toggle__sun { display: none; }
[data-theme="dark"] .ib-theme-toggle__moon { display: block; }
.ib-nav .ib-btn-primary { display: none; padding: .55rem 1.1rem; font-size: .875rem; }
.ib-mobile-menu {
  display: none; padding: 1rem 1.25rem 1.5rem;
  border-top: 1px solid var(--ib-line); background: var(--ib-bg-soft);
}
.ib-mobile-menu.open { display: block; }
/* Never let the open menu run off a short screen (landscape phones). */
.ib-mobile-menu.open { max-height: calc(100vh - 4.25rem); max-height: calc(100dvh - 4.25rem); overflow-y: auto; }
.ib-mobile-menu a {
  display: block; padding: .65rem 0; color: var(--ib-ink);
  font-weight: 500; border-bottom: 1px solid var(--ib-line);
}
.ib-mobile-menu a:last-of-type { border-bottom: none; }
@media (min-width: 900px) {
  .ib-nav-links { display: flex; }
  .ib-nav .ib-btn-primary { display: inline-flex; }
  .ib-menu-toggle { display: none; }
}

/* --- Footer (mirror) ----------------------------------------------------- */
.ib-footer {
  background: var(--ib-footer-bg); color: var(--ib-footer-text);
  padding: 4rem 0 2rem; margin-top: 0;
}
/* .ib-footer a sets display:block and out-specifies .ib-logo, which collapses
   the gap between the mark and the wordmark. Restore it here. */
.ib-footer a.ib-logo { display: inline-flex; gap: .5rem; color: var(--ib-footer-text); padding: 0; }
.ib-footer h4 {
  color: var(--ib-footer-text); font-size: .78rem; letter-spacing: .16em;
  text-transform: uppercase; font-weight: 600; margin-bottom: 1rem; opacity: .7;
}
.ib-footer a { color: var(--ib-footer-text-soft); display: block; padding: .25rem 0; font-size: .92rem; }
/* On any touch device the footer is a column of 32px targets, and an iPad in
   landscape is 1024 CSS px wide, so a width query alone misses it. Ask about
   the pointer instead. Nothing else competes for the space down there. */
@media (hover: none), (max-width: 859px) {
  .ib-footer a { padding: .55rem 0; }
  .ib-footer-legal a { padding: .35rem 0; }
  .ib-nav .ib-logo { padding-block: .5rem; }
}
.ib-social-row a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.625rem; height: 2.625rem; margin-left: -0.5625rem; border-radius: 62.4375rem; padding: 0;
}
.ib-social-row a:hover { background: rgba(242,239,232,.08); }
.ib-footer a:hover { color: var(--ib-accent); }
.ib-footer p { color: var(--ib-footer-text-soft); font-size: .92rem; }
.ib-footer-grid { display: grid; gap: 2rem; grid-template-columns: 1fr; }
@media (min-width: 860px) { .ib-footer-grid { grid-template-columns: 1.4fr repeat(3, 1fr); } }
.ib-footer-bottom {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem;
  border-top: 1px solid var(--ib-footer-line); margin-top: 3rem; padding-top: 1.5rem;
  font-size: .82rem; color: var(--ib-footer-text-faint);
}
.ib-footer-legal { display: flex; gap: 1.25rem; flex-wrap: wrap; }
.ib-footer-legal a { display: inline; font-size: .82rem; color: var(--ib-footer-text-faint); }

/* --- Sticky CTA + scroll progress (mirror) ------------------------------- */
.ib-scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 70;
  background: linear-gradient(90deg, var(--ib-accent), var(--ib-gold));
  transform: scaleX(0); transform-origin: 0 50%; pointer-events: none;
  will-change: transform;
}
.ib-sticky-cta {
  position: fixed; left: 50%; bottom: 1rem; transform: translate(-50%, 0); z-index: 60;
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .95rem 1.4rem; background: var(--sx-accent-solid); color: var(--sx-on-accent);
  border-radius: 62.4375rem; font-size: .95rem; font-weight: 600;
  box-shadow: 0 12px 32px -8px rgba(32,32,30,.35), 0 2px 4px rgba(32,32,30,.18);
  border: 1px solid color-mix(in srgb, var(--ib-accent) 70%, #000);
  transition: opacity .2s, transform .25s, background .15s;
  white-space: nowrap; max-width: calc(100% - 2rem);
}
.ib-sticky-cta:hover { background: var(--ib-accent-hover); color: var(--sx-on-accent); }
.ib-sticky-cta.is-hidden { opacity: 0; transform: translate(-50%, 120%); pointer-events: none; }
[data-theme="dark"] .ib-sticky-cta { box-shadow: 0 12px 32px -8px rgba(0,0,0,.55), 0 2px 4px rgba(0,0,0,.4); }

.sx-skip {
  position: absolute; left: -624.9375rem; top: 0; z-index: 100;
  background: var(--ib-accent-ink); color: #fff; padding: .75rem 1.25rem;
  border-radius: 0 0 var(--ib-radius-sm) 0;
}
.sx-skip:focus { left: 0; color: #fff; }


/* ==========================================================================
   PART B, SPACE EXPLORATION EXTENSION
   ========================================================================== */

/* --------------------------------------------------------------------------
   B.-1  Two accessibility tokens the brand is missing
   ---------------------------------------------------
   Two AA failures exist on insightbay.net today and would be inherited here
   verbatim. Both come from the same root cause: --ib-accent is a *surface*
   colour being used as a *text* colour, and no token says what colour text
   goes ON the accent.

     1. .ib-eyebrow uses --ib-accent. #C96442 on the cream #F5F1EB is 3.46:1.
        AA needs 4.5:1 for text this size. The brand already owns the fix, --ib-accent-ink (#B2502F) is 4.9:1 and is visually indistinguishable
        at eyebrow size.
     2. White text on the dark-mode accent #E8845E is 2.66:1. On a bright
        accent the label has to go dark; #17120F measures about 9:1.

   Both are recommended site-wide, not just here. See ACCESSIBILITY.md.
   -------------------------------------------------------------------------- */
:root {
  --sx-accent-text:  #B2502F;   /* accent used as TEXT, on a light surface */
  --sx-gold-text:    #8A6620;   /* --ib-gold is 2.95:1 on cream; this is 4.9 */
  --sx-accent-solid: #B2502F;   /* accent used as a filled SURFACE          */
  --sx-on-accent:    #FFFFFF;   /* label colour on that surface             */
}
[data-theme="dark"] {
  --sx-accent-text:  #E8845E;
  --sx-accent-solid: #E8845E;
  --sx-on-accent:    #17120F;
  --sx-gold-text:    #D9B265;   /* already 8.4:1 on the dark surface */
}
.ib-eyebrow { color: var(--sx-accent-text); }

/* --------------------------------------------------------------------------
   B.0  The void surface
   The one structural idea on this page. A .sx-void panel is permanently dark
   in both themes, the same move the footer already makes, and it re-points
   the brand tokens locally so every .ib-* component inside it stays correct.
   -------------------------------------------------------------------------- */
.sx-void {
  --ib-bg:            #0C0B0A;
  --ib-bg-soft:       #121110;
  --ib-bg-deep:       #171614;
  --ib-bg-hero-top:   #17150F;
  --ib-card-bg:       #141312;
  --ib-ink:           #F2EFE8;
  --ib-ink-soft:      #CAC4BA;
  --ib-ink-muted:     #8C867D;
  --ib-line:          #2A2723;
  --ib-line-strong:   #3C3833;
  --ib-accent:        #E8845E;
  --ib-accent-ink:    #E8845E;
  --ib-accent-ink-hover: #F19770;
  --ib-accent-hover:  #F19770;
  --ib-accent-soft:   #3D2A20;
  --ib-gold:          #D9B265;
  --ib-grid-line:     rgba(242,239,232,.05);
  --sx-accent-text:   #E8845E;
  --sx-accent-solid:  #E8845E;
  --sx-on-accent:     #17120F;
  --sx-gold-text:     #D9B265;
  --ib-shadow:        0 1px 2px rgba(0,0,0,.5), 0 0.625rem 1.875rem -0.625rem rgba(0,0,0,.7);
  --ib-shadow-lg:     0 0.375rem 1.125rem rgba(0,0,0,.5), 0 1.875rem 3.75rem -1.25rem rgba(0,0,0,.8);

  position: relative;
  isolation: isolate;
  background: var(--ib-bg);
  color: var(--ib-ink);
  overflow: hidden;
}
.sx-void h1, .sx-void h2, .sx-void h3, .sx-void h4 { color: var(--ib-ink); }
.sx-void p { color: var(--ib-ink-soft); }
.sx-void .ib-btn-primary { background: var(--ib-ink); color: #14120F; }
.sx-void .ib-btn-primary:hover { background: #fff; color: #14120F; }
/* ACCESSIBILITY FIX, please read before "correcting" this back.
   The brand's accent button is white text on --ib-accent-ink. In light mode
   that is #fff on #B2502F = 4.6:1 and passes AA. In DARK mode the site raises
   --ib-accent-ink to #E8845E, and #fff on #E8845E is 2.66:1, a WCAG AA
   failure that exists on insightbay.net today, on every dark-mode page.
   On a dark surface the correct move is to keep the bright accent and invert
   the label: #17120F on #E8845E measures about 9:1. Recommended site-wide. */
.sx-void .ib-btn-accent { background: var(--sx-accent-solid); color: var(--sx-on-accent); }
.sx-void .ib-btn-accent:hover { background: var(--ib-accent-hover); color: var(--sx-on-accent); }
.sx-void .ib-card { background: var(--ib-card-bg); border-color: var(--ib-line); }

/* Everything a void panel draws sits behind its content. */
.sx-void > .ib-container,
.sx-void > .sx-wide { position: relative; z-index: 2; }

/* --------------------------------------------------------------------------
   B.1  Deep-space background layers
   Three cheap layers, composited on the GPU, never repainted:
     .sx-stars, <canvas>, three parallax depths, drawn once per frame
     .sx-neb, CSS radial gradients, translated very slowly
     .sx-grain, a static SVG noise tile, kills gradient banding
   -------------------------------------------------------------------------- */
.sx-layer {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
}
.sx-stars { display: block; width: 100%; height: 100%; }

.sx-neb {
  background:
    radial-gradient(58% 44% at 18% 12%,  rgba(201,100,66,.20), transparent 62%),
    radial-gradient(46% 38% at 84% 26%,  rgba(122, 92, 160, .16), transparent 64%),
    radial-gradient(70% 50% at 52% 100%, rgba(181,138,58,.14), transparent 66%),
    radial-gradient(90% 70% at 50% 45%,  rgba(20,18,26,.55), transparent 70%);
  /* PERF: no filter:blur() here. Radial gradients are already soft, so the
     blur bought nothing visible and cost a full-layer re-raster every frame
     the layer moved. Measured: removing it roughly doubled scroll frame rate
     in software rasterisation. */
  /* Oversized once, so translation never exposes an edge. */
  transform: translate3d(0,0,0) scale(1.18);
  opacity: .9;
}
/* Aurora glow, the warm light that seems to come from below the horizon.

   PERF NOTE, because this looks like an odd way to write it:
   this started as a separate .sx-aurora element with a conic-gradient and
   filter: blur(38px). Two problems. A 38 px blur across a full-viewport layer
   is among the most expensive things a compositor can be asked for, and it
   was a SECOND full-viewport promoted layer stacked on the nebula, which
   overlaps it almost exactly. Both are now folded into the single .sx-neb
   layer on the two panels that need them, built from wide elliptical
   gradients that are soft by construction. One layer, no filter, same look.
   Measured on software rasterisation with no GPU at all: 7 fps to 60. */
.sx-hero .sx-neb,
.sx-final .sx-neb {
  background:
    radial-gradient(58% 44% at 18% 12%,  rgba(201,100,66,.20), transparent 62%),
    radial-gradient(46% 38% at 84% 26%,  rgba(122,92,160,.16), transparent 64%),
    radial-gradient(75% 55% at 22% 108%, rgba(201,100,66,.26), transparent 72%),
    radial-gradient(65% 48% at 58% 116%, rgba(181,138,58,.18), transparent 70%),
    radial-gradient(90% 60% at 88% 104%, rgba(122,92,160,.14), transparent 74%),
    radial-gradient(90% 70% at 50% 45%,  rgba(20,18,26,.55), transparent 70%);
  will-change: transform;
  animation: sx-drift 68s var(--ibe-out) infinite alternate;
}
@keyframes sx-drift {
  /* Translate only. The original keyframes also animated scale() from 1.12 to
     1.18, and scaling a promoted layer re-rasterises it at every new scale
     factor, which defeats the point of promoting it. The scale is fixed on
     the base rule; only the position moves. */
  0%   { transform: translate3d(-1.6%,  1.4%, 0) scale(1.18); }
  100% { transform: translate3d( 1.6%, -1.4%, 0) scale(1.18); }
}

.sx-grain {
  /* PERF: no mix-blend-mode. A blend mode forces the entire stacking context
     to be composited on every frame instead of taking the fast path; at 4.5%
     opacity over a near-black surface the visual difference is nil. */
  opacity: .05;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='.7'/></svg>");
}

/* PERF: a void panel's ambient layers only animate while that panel is on
   screen. There are five void panels; without this, five full-width gradient
   layers are being stepped forward at all times, four of them invisibly.
   JS adds .is-onscreen via IntersectionObserver. */
.sx-void:not(.is-onscreen) .sx-neb,
.sx-void:not(.is-onscreen) .sx-meteor,
.sx-void:not(.is-onscreen) .sx-orbit-spin { animation-play-state: paused; }

/* A hairline horizon that closes a void panel without a hard edge. */
.sx-void::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(232,132,94,.35), transparent);
  z-index: 3; pointer-events: none;
}

/* Mouse / scroll parallax. JS writes --sx-px and --sx-py in the -1..1 range. */
.sx-parallax {
  transform: translate3d(calc(var(--sx-px, 0) * var(--sx-depth, 0.375rem)),
                         calc(var(--sx-py, 0) * var(--sx-depth, 0.375rem)), 0);
  transition: transform .5s var(--ibe-out);
  will-change: transform;
}

/* --------------------------------------------------------------------------
   B.2  Hero
   -------------------------------------------------------------------------- */
.sx-hero { padding-block: clamp(4.5rem, 11vh, 8rem) clamp(3.5rem, 9vh, 6.5rem); }
.sx-hero-grid { display: grid; gap: 3rem; align-items: center; }
@media (min-width: 1000px) { .sx-hero-grid { grid-template-columns: 1.08fr .92fr; gap: 4rem; } }

.sx-hero h1 {
  font-size: clamp(2.6rem, 5.6vw, 4.35rem);
  line-height: 1.04;
  letter-spacing: -.03em;
  margin-top: 1.1rem;
}
.sx-hero h1 .sx-accent { color: var(--ib-accent); display: block; }
.sx-hero-sub {
  margin-top: 1.5rem; font-size: clamp(1.05rem, 1.5vw, 1.2rem);
  max-width: 34ch; color: var(--ib-ink-soft);
}
.sx-hero-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2.25rem; }

/* The four facts a parent needs before they scroll. */
.sx-facts {
  display: grid; grid-template-columns: repeat(2, minmax(0,1fr));
  gap: 1px; margin-top: 3rem;
  background: var(--ib-line); border: 1px solid var(--ib-line);
  border-radius: var(--ib-radius); overflow: hidden;
}
@media (min-width: 720px) { .sx-facts { grid-template-columns: repeat(4, minmax(0,1fr)); } }
.sx-fact { background: var(--ib-bg); padding: 1.1rem 1.15rem; }
.sx-fact dt {
  font-family: var(--ib-font-mono); font-size: 1.5rem; font-weight: 500;
  color: var(--ib-accent); letter-spacing: -.02em; line-height: 1.1;
}
.sx-fact dd { margin: .35rem 0 0; font-size: .82rem; color: var(--ib-ink-muted); line-height: 1.45; }

/* Hero art: an orbital diagram that draws itself, not a decorative blob. */
.sx-orbit-wrap { position: relative; aspect-ratio: 1 / 1; max-width: 31.25rem; margin-inline: auto; width: 100%; }
.sx-orbit { width: 100%; height: 100%; overflow: visible; }
.sx-orbit .ring { fill: none; stroke: rgba(242,239,232,.16); stroke-width: 1; }
.sx-orbit .ring-lit { stroke: rgba(232,132,94,.55); stroke-dasharray: 1 1; }
.sx-orbit .planet { fill: url(#sxPlanet); }
.sx-orbit .halo { fill: url(#sxHalo); }
.sx-orbit .tick { stroke: rgba(242,239,232,.28); stroke-width: 1; }
.sx-orbit .label {
  font-family: var(--ib-font-mono); font-size: 9.5px; letter-spacing: .16em;
  fill: rgba(242,239,232,.5); text-transform: uppercase;
}
.sx-orbit .craft { fill: var(--ib-accent); }
.sx-orbit-labels text {
  text-anchor: middle;
  paint-order: stroke;
  stroke: #0C0B0A; stroke-width: 5px; stroke-linejoin: round;
}
.sx-orbit-spin { transform-origin: 250px 250px; animation: sx-spin 44s linear infinite; }
@keyframes sx-spin { to { transform: rotate(360deg); } }

/* Constellation overlay: strokes draw themselves once, on entry. */
.sx-constellation path, .sx-constellation line {
  stroke: rgba(242,239,232,.30); stroke-width: 1; fill: none;
  stroke-dasharray: var(--len, 400); stroke-dashoffset: var(--len, 400);
}
.is-visible .sx-constellation path,
.is-visible .sx-constellation line {
  animation: sx-draw 2.4s var(--ibe-out) forwards;
}
@keyframes sx-draw { to { stroke-dashoffset: 0; } }
.sx-constellation circle { fill: rgba(242,239,232,.75); }

/* Meteors: two, rare, never in the reader's way. */
.sx-meteor {
  position: absolute; width: 9.375rem; height: 1px; z-index: 1;
  background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.85));
  opacity: 0; transform: rotate(24deg);
  animation: sx-meteor 14s linear infinite;
}
.sx-meteor--2 { animation-delay: 7.5s; animation-duration: 19s; width: 6.875rem; }
@keyframes sx-meteor {
  0%   { opacity: 0; transform: translate3d(0,0,0) rotate(24deg); }
  2%   { opacity: .9; }
  9%   { opacity: 0; transform: translate3d(46vw, 22vw, 0) rotate(24deg); }
  100% { opacity: 0; transform: translate3d(46vw, 22vw, 0) rotate(24deg); }
}

/* --------------------------------------------------------------------------
   B.3  Chapter headers, the page reads as chapters, so they are numbered.
   -------------------------------------------------------------------------- */
.sx-chapter { max-width: 47.5rem; }
.sx-chapter .ib-eyebrow { display: flex; align-items: baseline; gap: .8rem; }
.sx-chapter .sx-num {
  font-family: var(--ib-font-mono); font-size: .8rem; letter-spacing: .1em;
  color: var(--ib-ink-muted); font-weight: 400;
}
.sx-chapter h2 { margin-top: 1rem; font-size: clamp(1.9rem, 3.6vw, 2.75rem); }
.sx-chapter .sx-lede {
  margin-top: 1.1rem; font-size: clamp(1.05rem, 1.4vw, 1.18rem);
  color: var(--ib-ink-soft); max-width: 62ch;
}
.sx-body { max-width: 62ch; }
.sx-body p + p { margin-top: 1.1rem; }
.sx-body p { color: var(--ib-ink-soft); font-size: 1.05rem; }

.sx-pull {
  margin: 2.5rem 0 0; padding-left: 1.5rem;
  border-left: 2px solid var(--ib-accent);
  font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  line-height: 1.35; letter-spacing: -.015em;
  color: var(--ib-ink); font-weight: 600; max-width: 26ch;
}
.sx-pull cite { display: block; margin-top: .85rem; font-size: .85rem; font-style: normal;
  font-weight: 400; letter-spacing: .04em; color: var(--ib-ink-muted); }

/* --------------------------------------------------------------------------
   B.4  Mars scene, the "where it all points" panel
   -------------------------------------------------------------------------- */
.sx-mars { padding-block: clamp(4rem, 9vh, 7rem) 0; }
.sx-mars-stage { position: relative; margin-top: 3rem; }
.sx-mars-svg { display: block; width: 100%; height: auto; }
.sx-mars-caption {
  display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; align-items: baseline;
  font-family: var(--ib-font-mono); font-size: .72rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ib-ink-muted);
  padding-bottom: 1.25rem;
}
.sx-mars-caption b { color: var(--ib-accent); font-weight: 500; }
/* The rover crosses the crater as you scroll, and crosses back as you scroll
   up. space.js writes --sx-rover-x on the <svg> in viewBox units; both the
   vehicle and the clip that reveals its trail read the same number, so the
   track can never get ahead of the wheels. Transform only, one composited
   layer, no layout and no repaint. */
.sx-mars-svg { --sx-rover-x: 31.875rem; }
.sx-rover { transform: translateX(var(--sx-rover-x)); will-change: transform; }
.sx-trail-clip { transform: translateX(var(--sx-rover-x)); }

/* On a phone the scene would otherwise collapse to a 130px strip. Fix the
   height and let preserveAspectRatio="slice" crop the sides instead, which
   also means the rover enters and leaves the frame properly. */
@media (max-width: 700px) {
  .sx-mars-svg { height: 13.125rem; }
}

/* --------------------------------------------------------------------------
   B.5  The eight fields × three stages explorer
   The centrepiece. One control, twenty-four real syllabi behind it.
   -------------------------------------------------------------------------- */
.sx-stage-switch {
  display: inline-flex; padding: 0.25rem; gap: 0.25rem; margin-top: 2rem;
  background: var(--ib-bg-deep); border: 1px solid var(--ib-line);
  border-radius: 62.4375rem; position: relative; flex-wrap: wrap;
}
.sx-stage-switch button {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  font-family: inherit; font-size: .88rem; font-weight: 500;
  color: var(--ib-ink-muted); padding: .6rem 1.15rem; border-radius: 62.4375rem;
  transition: color var(--ib-dur-1), background var(--ib-dur-2) var(--ibe-out);
  white-space: nowrap;
}
.sx-stage-switch button:hover { color: var(--ib-ink); }
.sx-stage-switch button[aria-selected="true"] {
  background: var(--sx-accent-solid); color: var(--sx-on-accent);
  box-shadow: 0 2px 10px -2px rgba(201,100,66,.5);
}
.sx-stage-switch .sx-sw-grade {
  font-family: var(--ib-font-mono); font-size: .72rem; opacity: .75; margin-right: .5rem;
}

.sx-stage-head { margin-top: 2.25rem; display: grid; gap: 1.5rem; }
@media (min-width: 900px) { .sx-stage-head { grid-template-columns: 1fr auto; align-items: end; } }
.sx-stage-head h3 { font-size: clamp(1.4rem, 2.4vw, 1.9rem); letter-spacing: -.02em; }
.sx-stage-head p { margin-top: .6rem; color: var(--ib-ink-soft); max-width: 68ch; font-size: 1rem; }
.sx-stage-stats { display: flex; gap: 1.75rem; }
.sx-stage-stats div { text-align: left; }
.sx-stage-stats b {
  display: block; font-family: var(--ib-font-mono); font-size: 1.6rem;
  font-weight: 500; color: var(--ib-accent); line-height: 1;
}
.sx-stage-stats span { font-size: .76rem; color: var(--ib-ink-muted); letter-spacing: .02em; }

.sx-fields {
  display: grid; gap: 1rem; margin-top: 2.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16.875rem), 1fr));
}
.sx-field {
  border: 1px solid var(--ib-line); border-radius: var(--ib-radius);
  background: var(--ib-card-bg); padding: 1.5rem 1.5rem 1.6rem;
  position: relative; overflow: hidden;
  transition: border-color var(--ib-dur-2), transform var(--ib-dur-2) var(--ibe-out), box-shadow var(--ib-dur-2);
}
.sx-field::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 0% 0%, rgba(232,132,94,.10), transparent 55%);
  opacity: 0; transition: opacity var(--ib-dur-2); pointer-events: none;
}
.sx-field:hover, .sx-field:focus-within {
  border-color: var(--ib-line-strong); transform: translateY(-0.1875rem); box-shadow: var(--ib-shadow);
}
.sx-field:hover::before, .sx-field:focus-within::before { opacity: 1; }
.sx-field-top { display: flex; align-items: flex-start; gap: .85rem; }
.sx-field-icon {
  flex: 0 0 auto; width: 2.375rem; height: 2.375rem; border-radius: 0.625rem;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ib-accent-soft); color: var(--ib-accent);
  transition: transform var(--ib-dur-2) var(--ibe-spring);
}
.sx-field:hover .sx-field-icon { transform: translateY(-2px) rotate(-4deg); }
.sx-field-icon svg { width: 1.25rem; height: 1.25rem; }
.sx-field h4 { font-size: 1.08rem; font-weight: 700; letter-spacing: -.01em; }
.sx-field .sx-field-tag {
  display: block; margin-top: .2rem; font-size: .85rem; color: var(--ib-ink-muted);
}
.sx-field ul { margin-top: 1.15rem; display: grid; gap: .55rem; }
.sx-field li {
  position: relative; padding-left: 1.1rem; font-size: .9rem;
  color: var(--ib-ink-soft); line-height: 1.45;
}
.sx-field li::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: 0.3125rem; height: 0.3125rem; border-radius: 50%; background: var(--ib-accent); opacity: .8;
}
/* Content swap: fade + rise, staggered by index via --i. */
.sx-field[data-swapping] { }
.sx-field ul.is-swapping li { opacity: 0; transform: translateY(0.375rem); }
.sx-field ul li {
  opacity: 1; transform: none;
  transition: opacity .34s var(--ibe-out), transform .34s var(--ibe-out);
  transition-delay: calc(var(--i, 0) * 28ms);
}

.sx-overlap {
  margin-top: 2rem; padding: 1.5rem 1.6rem;
  border: 1px dashed var(--ib-line-strong); border-radius: var(--ib-radius);
  background: transparent; display: grid; gap: .9rem;
}
@media (min-width: 820px) { .sx-overlap { grid-template-columns: 11.875rem 1fr; gap: 2rem; align-items: start; } }
.sx-overlap h4 { font-size: .95rem; letter-spacing: -.005em; }
.sx-overlap p { font-size: .95rem; color: var(--ib-ink-soft); }

/* --------------------------------------------------------------------------
   B.6  Twelve-year timeline
   -------------------------------------------------------------------------- */
.sx-timeline { margin-top: 3rem; display: grid; gap: 1.25rem; }
@media (min-width: 940px) { .sx-timeline { grid-template-columns: repeat(3, 1fr); gap: 1.5rem; } }
.sx-tl {
  position: relative; border: 1px solid var(--ib-line); border-radius: var(--ib-radius);
  background: var(--ib-bg-soft); padding: 1.75rem 1.6rem 1.6rem;
  overflow: hidden;
}
.sx-tl::before {
  content: ""; position: absolute; top: 0; left: 0; height: 0.1875rem; width: 100%;
  background: linear-gradient(90deg, var(--ib-accent), var(--ib-gold));
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 1.1s var(--ibe-out);
}
.sx-tl.is-visible::before { transform: scaleX(1); }
.sx-tl:nth-child(2)::before { transition-delay: .12s; }
.sx-tl:nth-child(3)::before { transition-delay: .24s; }
.sx-tl-grade {
  font-family: var(--ib-font-mono); font-size: .78rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--sx-gold-text);
}
.sx-tl h3 { margin-top: .5rem; font-size: 1.45rem; }
.sx-tl .sx-tl-line { margin-top: .35rem; color: var(--ib-ink-muted); font-size: .92rem; }
.sx-tl p { margin-top: 1rem; font-size: .95rem; color: var(--ib-ink-soft); }
.sx-tl ul { margin-top: 1.2rem; display: grid; gap: .5rem; border-top: 1px solid var(--ib-line); padding-top: 1.2rem; }
.sx-tl li { font-size: .88rem; color: var(--ib-ink-soft); padding-left: 1.35rem; position: relative; }
.sx-tl li::before {
  content: "→"; position: absolute; left: 0; color: var(--ib-accent);
  font-size: .82rem; line-height: 1.6;
}
.sx-tl-sub {
  margin-top: 1.4rem; font-family: var(--ib-font-mono); font-size: .74rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ib-ink-muted);
}
.sx-tl-sub + ul { margin-top: .8rem; border-top: 0; padding-top: 0; }
.sx-tl-end {
  margin-top: 1.4rem; padding-top: 1.2rem; border-top: 1px solid var(--ib-line);
  font-size: .92rem; color: var(--ib-ink-soft);
}
.sx-tl-end b {
  display: block; margin-bottom: .45rem;
  font-family: var(--ib-font-mono); font-size: .74rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--sx-accent-text); font-weight: 700;
}

/* --------------------------------------------------------------------------
   B.7  The rocket-equation interactive
   -------------------------------------------------------------------------- */
.sx-rocket { display: grid; gap: 2.5rem; margin-top: 3rem; align-items: start; }
@media (min-width: 980px) { .sx-rocket { grid-template-columns: 1.05fr .95fr; gap: 3.5rem; } }

.sx-eq {
  font-family: var(--ib-font-mono); font-size: clamp(1.05rem, 2vw, 1.35rem);
  color: var(--ib-ink); background: var(--ib-bg-deep);
  border: 1px solid var(--ib-line); border-radius: var(--ib-radius);
  padding: 1.4rem 1.5rem; margin-top: 1.5rem; overflow-x: auto;
  display: flex; align-items: center; gap: .1rem; line-height: 1.9;
}
.sx-frac { display: inline-flex; flex-direction: column; text-align: center; vertical-align: middle;
  margin: 0 .35rem; font-size: .82em; }
/* Direct children only, otherwise the <span class="sx-sub"> inside each
   numerator also matches :first-child and gets a stray rule under it. */
.sx-frac > span:first-child { border-bottom: 1px solid currentColor; padding: 0 .35rem .12rem; }
.sx-frac > span:last-child { padding: .12rem .35rem 0; }
.sx-sub { font-size: .68em; vertical-align: sub; }
.sx-sup { font-size: .68em; vertical-align: super; }

.sx-sliders { display: grid; gap: 1.5rem; margin-top: 1.75rem; }
.sx-slider label {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  font-size: .9rem; color: var(--ib-ink-soft); margin-bottom: .6rem;
}
.sx-slider output {
  font-family: var(--ib-font-mono); font-size: 1rem; color: var(--ib-accent); font-weight: 500;
}
/* The control is 28px tall and transparent; the 3px rail is drawn on the track
   pseudo-element. A 3px-tall input is a 3px-tall touch target, which is the
   difference between a thing a parent drags and a thing they give up on. */
.sx-slider input[type="range"] {
  -webkit-appearance: none; appearance: none; width: 100%; height: 1.75rem;
  background: transparent; outline-offset: 4px; cursor: pointer; margin: 0;
}
.sx-slider input[type="range"]::-webkit-slider-runnable-track {
  height: 0.1875rem; border-radius: 62.4375rem; background: var(--ib-line-strong);
}
.sx-slider input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 1.375rem; height: 1.375rem;
  border-radius: 50%; background: var(--ib-accent); cursor: grab;
  border: 3px solid var(--ib-bg);
  box-shadow: 0 2px 8px -1px rgba(0,0,0,.45);
  margin-top: -0.59375rem;
  transition: transform var(--ib-dur-1) var(--ibe-spring);
}
.sx-slider input[type="range"]::-webkit-slider-thumb:active { cursor: grabbing; transform: scale(1.15); }
.sx-slider input[type="range"]::-moz-range-track {
  height: 0.1875rem; border-radius: 62.4375rem; background: var(--ib-line-strong);
}
.sx-slider input[type="range"]::-moz-range-thumb {
  width: 1.375rem; height: 1.375rem; border-radius: 50%; background: var(--ib-accent);
  cursor: grab; border: 3px solid var(--ib-bg);
}

/* The vehicle: a single column that fills with propellant as you drag. */
.sx-vehicle { display: grid; grid-template-columns: 4.875rem 1fr; gap: 1.75rem; align-items: start; }
.sx-stack {
  position: relative; border: 1px solid var(--ib-line-strong);
  border-radius: 2.5rem 2.5rem 0.625rem 0.625rem; overflow: hidden;
  background: var(--ib-bg-deep); height: 21.25rem;
  display: flex; flex-direction: column-reverse;
}
.sx-stack-fuel {
  background: linear-gradient(180deg, var(--ib-accent) 0%, #8f3d24 100%);
  height: var(--sx-fuel, 90%);
  transition: height .55s var(--ibe-out);
  position: relative;
}
.sx-stack-fuel::after {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: rgba(255,255,255,.55);
}
.sx-stack-dry {
  flex: 1 1 auto;
  background: repeating-linear-gradient(135deg,
    transparent 0 0.3125rem, var(--ib-grid-line) 0.3125rem 0.375rem);
}
.sx-readout { display: grid; gap: 1rem; align-content: center; }
.sx-readout div { border-left: 2px solid var(--ib-line); padding-left: .95rem; }
.sx-readout b {
  display: block; font-family: var(--ib-font-mono); font-size: 1.7rem;
  font-weight: 500; color: var(--ib-ink); letter-spacing: -.02em; line-height: 1.1;
}
.sx-readout span { font-size: .78rem; color: var(--ib-ink-muted); letter-spacing: .02em; }
.sx-readout .sx-hot b { color: var(--ib-accent); }
.sx-verdict {
  margin-top: 1.5rem; font-size: .92rem; padding: .9rem 1.05rem;
  border-radius: var(--ib-radius-sm); border: 1px solid var(--ib-line);
  background: var(--ib-bg-deep); color: var(--ib-ink-soft);
}
.sx-note {
  margin-top: 1.5rem; font-size: .82rem; color: var(--ib-ink-muted);
  border-top: 1px solid var(--ib-line); padding-top: 1rem; max-width: 62ch;
}

/* Three-ages ladder */
.sx-ages { display: grid; gap: 1rem; margin-top: 2.5rem; }
@media (min-width: 900px) { .sx-ages { grid-template-columns: repeat(3, 1fr); } }
.sx-age {
  border: 1px solid var(--ib-line); border-radius: var(--ib-radius);
  background: var(--ib-card-bg); padding: 1.6rem 1.7rem;
}
.sx-age .grade {
  font-size: .78rem; letter-spacing: .14em; text-transform: uppercase;
  font-weight: 600; color: var(--ib-accent);
}
.sx-age h3 { margin: .5rem 0 .7rem; font-size: 1.15rem; }
.sx-age p { font-size: .93rem; color: var(--ib-ink-soft); }
.sx-age p + p { margin-top: .75rem; }

/* --------------------------------------------------------------------------
   B.8  Evidence / outcomes / careers
   -------------------------------------------------------------------------- */
.sx-cols { display: grid; gap: 1rem; margin-top: 2.5rem; }
@media (min-width: 760px)  { .sx-cols-2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px)  { .sx-cols-3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1000px) { .sx-cols-4 { grid-template-columns: repeat(4, 1fr); } }

.sx-tile {
  border: 1px solid var(--ib-line); border-radius: var(--ib-radius);
  padding: 1.5rem 1.55rem; background: var(--ib-bg-soft);
  transition: border-color var(--ib-dur-2), transform var(--ib-dur-2) var(--ibe-out);
}
.sx-tile:hover { border-color: var(--ib-line-strong); transform: translateY(-2px); }
.sx-tile h4 { font-size: 1rem; }
.sx-tile .sx-kicker {
  font-family: var(--ib-font-mono); font-size: .74rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--sx-gold-text); display: block; margin-bottom: .7rem;
}
.sx-tile p { margin-top: .55rem; font-size: .92rem; color: var(--ib-ink-soft); }
.sx-tile ul { margin-top: .9rem; display: grid; gap: .45rem; }
.sx-tile li { font-size: .88rem; color: var(--ib-ink-soft); padding-left: 1rem; position: relative; }
.sx-tile li::before {
  content: ""; position: absolute; left: 0; top: .58em; width: 0.25rem; height: 0.25rem;
  border-radius: 50%; background: var(--ib-accent);
}

/* Employer marquee, static list, no scrolling gimmick, just typography. */
.sx-employers {
  margin-top: 2rem; display: flex; flex-wrap: wrap; gap: .55rem;
}
.sx-employers span {
  font-family: var(--ib-font-mono); font-size: .76rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ib-ink-soft);
  border: 1px solid var(--ib-line); border-radius: 62.4375rem; padding: .42rem .9rem;
  transition: border-color var(--ib-dur-2), color var(--ib-dur-2);
}
.sx-employers span:hover { border-color: var(--ib-accent); color: var(--ib-accent); }

/* The ITAR argument gets its own emphasis slab. */
.sx-slab {
  border-radius: var(--ib-radius-lg); padding: clamp(2rem, 4vw, 3.25rem);
  background: var(--ib-emphasis-bg); color: var(--ib-emphasis-text);
  border: 1px solid var(--ib-emphasis-line); margin-top: 3rem;
}
.sx-slab h3 { color: var(--ib-emphasis-text); font-size: clamp(1.35rem, 2.6vw, 1.85rem); max-width: 24ch; }
.sx-slab p { color: var(--ib-emphasis-text-soft); margin-top: 1.1rem; max-width: 64ch; font-size: 1.02rem; }
.sx-slab .sx-slab-grid {
  margin-top: 2.25rem; display: grid; gap: 1.5rem; border-top: 1px solid var(--ib-emphasis-line); padding-top: 2rem;
}
@media (min-width: 820px) { .sx-slab .sx-slab-grid { grid-template-columns: repeat(3, 1fr); gap: 2rem; } }
/* On wide screens the slab reads as a spread: claim on the left, argument on
   the right. Left-aligning both would leave half the slab empty. */
@media (min-width: 940px) {
  .sx-slab { display: grid; grid-template-columns: minmax(0,.92fr) minmax(0,1.08fr); column-gap: 3.5rem; }
  .sx-slab > h3 { grid-column: 1; max-width: 18ch; }
  .sx-slab > p  { grid-column: 2; margin-top: .3rem; max-width: none; }
  .sx-slab > .sx-slab-grid { grid-column: 1 / -1; }
}
.sx-slab .sx-slab-grid h4 { color: var(--ib-emphasis-text); font-size: .95rem; }
.sx-slab .sx-slab-grid p { color: var(--ib-emphasis-text-faint); font-size: .9rem; margin-top: .4rem; }

/* --------------------------------------------------------------------------
   B.9  How it runs / objections / FAQ
   -------------------------------------------------------------------------- */
.sx-runs { display: grid; gap: 2rem; margin-top: 2.5rem; }
@media (min-width: 880px) { .sx-runs { grid-template-columns: repeat(3, 1fr); gap: 2.5rem; } }
.sx-run h4 { font-size: 1.05rem; }
.sx-run p { margin-top: .6rem; font-size: .94rem; color: var(--ib-ink-soft); }
.sx-run-rule { height: 2px; width: 2.125rem; background: var(--ib-accent); margin-bottom: 1.1rem; }

.sx-faq { margin-top: 2.5rem; max-width: 53.75rem; border-top: 1px solid var(--ib-line); }
.sx-faq details { border-bottom: 1px solid var(--ib-line); }
.sx-faq summary {
  list-style: none; cursor: pointer; padding: 1.3rem 3rem 1.3rem 0;
  font-weight: 600; font-size: 1.03rem; color: var(--ib-ink);
  position: relative; transition: color var(--ib-dur-1);
}
.sx-faq summary::-webkit-details-marker { display: none; }
.sx-faq summary:hover { color: var(--ib-accent-ink); }
.sx-faq summary::after {
  content: ""; position: absolute; right: .35rem; top: 50%;
  width: 0.6875rem; height: 0.6875rem; margin-top: -0.4375rem;
  border-right: 2px solid var(--ib-accent); border-bottom: 2px solid var(--ib-accent);
  transform: rotate(45deg); transform-origin: 60% 60%;
  transition: transform var(--ib-dur-2) var(--ibe-out);
}
.sx-faq details[open] summary::after { transform: rotate(-135deg); }
.sx-faq .sx-faq-body { padding: 0 0 1.5rem; max-width: 68ch; }
.sx-faq .sx-faq-body p { color: var(--ib-ink-soft); font-size: .98rem; }
.sx-faq .sx-faq-body p + p { margin-top: .85rem; }
.sx-faq details[open] .sx-faq-body { animation: sx-fade .4s var(--ibe-out); }
@keyframes sx-fade { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

/* Educator */
.sx-educator { display: grid; gap: 2.5rem; align-items: center; margin-top: 2.5rem; }
@media (min-width: 900px) { .sx-educator { grid-template-columns: 16.75rem 1fr; gap: 3.5rem; } }
.sx-portrait {
  aspect-ratio: 4 / 5; border-radius: var(--ib-radius-lg); overflow: hidden;
  border: 1px solid var(--ib-line); background: var(--ib-bg-deep);
  position: relative; margin: 0;
}
/* A real photograph, not a monogram. Sized by the frame and cropped by the
   image, so the ratio is reserved before the file arrives and nothing shifts. */
.sx-portrait img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%; }
/* A hairline warm wash stops a greyscale headshot reading as stock photography
   dropped onto a cream page. */
.sx-portrait::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(201,100,66,.07), rgba(32,32,30,.10));
  mix-blend-mode: multiply;
}
/* In dark mode a light-background headshot is the brightest object on the page
   and pulls the eye away from the quote beside it. Sit it back into the surface. */
[data-theme="dark"] .sx-portrait::after {
  background: linear-gradient(180deg, rgba(232,132,94,.10), rgba(0,0,0,.34));
  mix-blend-mode: normal;
}
[data-theme="dark"] .sx-portrait img { filter: brightness(.86) contrast(1.03); }
.sx-void .sx-portrait img { filter: brightness(.86) contrast(1.03); }
/* On a phone a full-width 4:5 photograph is 480px of face. Cap it. */
@media (max-width: 899px) { .sx-portrait { max-width: 16.125rem; } }
.sx-quote {
  font-size: clamp(1.2rem, 2.2vw, 1.5rem); line-height: 1.4;
  letter-spacing: -.015em; font-weight: 600; color: var(--ib-ink); max-width: 30ch;
}
.sx-credentials { margin-top: 1.75rem; display: grid; gap: .55rem; }
.sx-credentials li { font-size: .93rem; color: var(--ib-ink-soft); padding-left: 1.5rem; position: relative; }
.sx-credentials li::before {
  content: ""; position: absolute; left: 0; top: .45em; width: 0.5625rem; height: 0.3125rem;
  border-left: 2px solid var(--ib-success); border-bottom: 2px solid var(--ib-success);
  transform: rotate(-45deg);
}

/* --------------------------------------------------------------------------
   B.10  Final CTA
   -------------------------------------------------------------------------- */
.sx-final { padding-block: clamp(5rem, 12vh, 8rem); text-align: center; }
.sx-final h2 { font-size: clamp(2rem, 4.4vw, 3.1rem); max-width: 18ch; margin-inline: auto; letter-spacing: -.03em; }
.sx-final .sx-lede { margin-inline: auto; text-align: center; }
.sx-final-actions { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; margin-top: 2.25rem; }
.sx-final-fine {
  margin-top: 2.5rem; font-family: var(--ib-font-mono); font-size: .74rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ib-ink-muted);
}

/* Stage recap under the final call to action. Three statements, no links:
   nothing on this page is downloadable, so the plan is stated here instead. */
.sx-recap {
  display: grid; gap: 1rem; margin-top: 3rem; text-align: left;
  max-width: 58.75rem; margin-inline: auto;
}
@media (min-width: 820px) { .sx-recap { grid-template-columns: repeat(3, 1fr); gap: 1.25rem; } }
.sx-recap > div {
  border-top: 2px solid var(--ib-accent);
  padding-top: 1.1rem;
}
.sx-recap b {
  display: block; font-family: var(--ib-font-mono); font-size: .74rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--sx-gold-text);
  font-weight: 500;
}
.sx-recap span { display: block; margin-top: .35rem; font-size: 1.15rem; font-weight: 700; color: var(--ib-ink); letter-spacing: -.01em; }
.sx-recap p { margin-top: .6rem; font-size: .9rem; color: var(--ib-ink-soft); line-height: 1.5; }

/* --------------------------------------------------------------------------
   B.11  Section rhythm and rules
   -------------------------------------------------------------------------- */
.sx-sec { padding-block: clamp(4.5rem, 9vh, 7rem); }
.sx-sec + .sx-sec:not(.sx-void) { border-top: 1px solid var(--ib-line); }
.sx-wide { max-width: 73.75rem; margin-inline: auto; padding-inline: 1.25rem; }
.sx-mt-1 { margin-top: 1rem; }
.sx-mt-2 { margin-top: 2rem; }
.sx-mt-3 { margin-top: 3rem; }

/* Nav sits over the hero until the hero has passed. Motion only, the nav is
   still the site nav, with the site's tokens, just temporarily transparent.

   To do that the nav has to overlay the hero rather than sit above it, so on
   THIS PAGE ONLY it is promoted from sticky to fixed and the hero pays back
   the 68px it took out of the flow. Scoped to body.sx-page so the shared
   component is untouched everywhere else. */
body.sx-page .ib-nav { position: fixed; top: 0; left: 0; right: 0; }
body.sx-page .sx-hero { padding-top: calc(4.25rem + clamp(3rem, 8vh, 6rem)); }
/* Anchor targets must clear the fixed bar. */
body.sx-page [id] { scroll-margin-top: 5.5rem; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

.ib-nav.sx-over {
  background: transparent; border-bottom-color: transparent;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* The over-hero ink swap lives on the bar row ONLY. The mobile menu panel is
   a sibling of .ib-nav-inner, so it keeps the page's real theme tokens and
   stays readable. Scoping these custom properties to .ib-nav itself made the
   open panel cream-on-cream in light mode (the invisible-menu bug). */
.ib-nav.sx-over .ib-nav-inner {
  --ib-ink: #F2EFE8; --ib-ink-soft: rgba(242,239,232,.78);
  --ib-line-strong: rgba(242,239,232,.28); --ib-bg-deep: rgba(242,239,232,.10);
  --ib-bg: #14120F;
}
.ib-nav.sx-over .ib-logo, .ib-nav.sx-over .ib-nav-links a { color: rgba(242,239,232,.82); }
.ib-nav.sx-over .ib-nav-links a:hover, .ib-nav.sx-over .ib-nav-links a.active { color: #F2EFE8; }
/* While the menu is open the nav is a menu surface, not a hero overlay.
   The page script adds .menu-open alongside the panel's .open; the bar takes
   its solid site surface back so logo, toggles and panel read in both themes. */
.ib-nav.sx-over.menu-open {
  background: var(--ib-nav-bg);
  border-bottom-color: var(--ib-line);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
.ib-nav.sx-over.menu-open .ib-nav-inner {
  --ib-ink: #20201E; --ib-ink-soft: #4A4742;
  --ib-line-strong: #C9C0AE; --ib-bg-deep: #EEE9DD; --ib-bg: #F5F1EB;
}
[data-theme="dark"] .ib-nav.sx-over.menu-open .ib-nav-inner {
  --ib-ink: #F2EFE8; --ib-ink-soft: #C9C4BB;
  --ib-line-strong: #45413A; --ib-bg-deep: #232220; --ib-bg: #1A1916;
}
.ib-nav.sx-over.menu-open .ib-logo { color: var(--ib-ink); }

/* --------------------------------------------------------------------------
   B.12  Motion & accessibility guards
   Everything above is decoration. Turn it all off on request, and the page
   still reads, still converts, still passes contrast.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .ib-reveal { opacity: 1 !important; transform: none !important; }
  .sx-tl::before { transform: scaleX(1) !important; }
  .sx-constellation path, .sx-constellation line { stroke-dashoffset: 0 !important; }
  .sx-meteor, .sx-aurora { display: none; }
  .sx-neb { animation: none; }
  .sx-parallax { transform: none !important; }
  /* the rover stops crossing; space.js pins it mid-crater */
}

@media print {
  .sx-layer, .ib-sticky-cta, .ib-scroll-progress, .ib-nav, .sx-meteor { display: none !important; }
  .sx-void { background: #fff !important; color: #000 !important; }
  .ib-reveal { opacity: 1 !important; transform: none !important; }
}

@media (forced-colors: active) {
  .sx-field, .sx-tile, .sx-tl { border: 1px solid CanvasText; }
  .sx-stage-switch button[aria-selected="true"] { forced-color-adjust: none; background: Highlight; color: HighlightText; }
}



/* ==========================================================================
   PART C, THE PHYSICS LAYER
   ==========================================================================

   /space is lit by a starfield. /mathematics is lit by graph paper. /physics
   is lit by field lines: the same near-black void surface, the same nebula,
   the same parallax dot canvas, but ruled by two families of smooth flux
   curves drifting past each other. The dots stop reading as stars and start
   reading as particles moving in a field, which is the whole idea of the page
   in one background layer.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   C.1  The field-line void
   Two superimposed SVG tiles, one fine and one coarse, translated very slowly
   in opposite directions. Each tile is a single cubic S-curve whose tangent at
   x = 0 and at x = tile width are identical, so the pattern repeats with no
   visible seam. No filter, no blend mode, one composited layer, exactly the
   same budget the nebula already runs on.
   -------------------------------------------------------------------------- */
.px-lines {
  --px-cell: 15rem;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='120'%3E%3Cpath d='M0 60 C 30 22 90 22 120 60 S 210 98 240 60' fill='none' stroke='%23F2EFE8' stroke-opacity='0.075' stroke-width='1'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='120'%3E%3Cpath d='M0 60 C 30 22 90 22 120 60 S 210 98 240 60' fill='none' stroke='%23E8845E' stroke-opacity='0.12' stroke-width='1.2'/%3E%3C/svg%3E");
  background-size:
    var(--px-cell) calc(var(--px-cell) / 2),
    calc(var(--px-cell) * 2.5) calc(var(--px-cell) * 1.25);
  /* Fade the ruling out at the edges so the panel has no visible seam. */
  -webkit-mask-image: radial-gradient(120% 92% at 50% 45%, #000 26%, transparent 80%);
          mask-image: radial-gradient(120% 92% at 50% 45%, #000 26%, transparent 80%);
  opacity: .9;
  animation: px-flux 120s linear infinite;
}
/* Promote the layer only while its panel is on screen. There are five void
   panels and two of them are thousands of pixels tall; pinning all five as
   compositor layers for the whole session costs real GPU memory for nothing. */
.sx-void.is-onscreen .px-lines { will-change: background-position; }
@keyframes px-flux {
  0%   { background-position: 0 0, 0 0; }
  100% { background-position: var(--px-cell) 0, calc(var(--px-cell) * -2.5) 0; }
}
.sx-void:not(.is-onscreen) .px-lines { animation-play-state: paused; }
@media (max-width: 700px) { .px-lines { --px-cell: 10.5rem; } }

/* --------------------------------------------------------------------------
   C.2  Hero: Newton's cannonball
   Not decoration. It is the oldest argument in the subject, and it is an
   argument a seven-year-old and a seventeen-year-old can both follow: fire it
   harder and the fall gets longer, until the ground curves away exactly as
   fast as the ball drops and it never lands at all. An orbit is a fall that
   keeps missing.

   The canvas is transparent on purpose. The dot field, the flux lines and the
   nebula behind it are other layers' work and have to show through. All the
   motion, the visibility gate and the phone haptics live in module 7b of
   physics.js; everything here is furniture.
   -------------------------------------------------------------------------- */
.px-cannon-wrap { position: relative; max-width: 35rem; margin-inline: auto; width: 100%; }
.px-cannon,
.px-cannon-static { display: block; width: 100%; height: auto; aspect-ratio: 600 / 490; }
.px-cannon { touch-action: manipulation; }

.px-cannon-cap {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem 1.125rem;
  flex-wrap: wrap; margin-top: 0.75rem;
  font-family: var(--ib-font-mono); font-size: 0.75rem; letter-spacing: .16em;
  text-transform: uppercase; color: rgba(242,239,232,.42);
}
.px-cannon-eq { color: rgba(242,239,232,.72); text-transform: none; letter-spacing: .10em; }
/* Written by physics.js every frame. tabular-nums so the row does not twitch
   as the digits change. */
.px-cannon-v {
  color: var(--ib-accent); font-variant-numeric: tabular-nums;
  min-width: 8.5ch; text-align: left;
}

/* Revealed by physics.js only where navigator.vibrate exists and the pointer
   is coarse, i.e. on a phone. On a desktop it never appears, because an inert
   control is worse than no control. */
.px-haptic {
  display: inline-flex; align-items: center; gap: 0.4375rem;
  font: inherit; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(242,239,232,.42); background: transparent;
  border: 1px solid var(--ib-line-strong); border-radius: 62.4375rem;
  padding: 0.3125rem 0.6875rem; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: color var(--ib-dur-1) var(--ibe-out), border-color var(--ib-dur-1) var(--ibe-out);
}
.px-haptic[hidden] { display: none; }
.px-haptic-dot {
  width: 0.375rem; height: 0.375rem; border-radius: 50%;
  background: var(--ib-line-strong);
  transition: background var(--ib-dur-1) var(--ibe-out);
}
.px-haptic[aria-pressed="true"] { color: rgba(242,239,232,.72); border-color: rgba(232,132,94,.45); }
.px-haptic[aria-pressed="true"] .px-haptic-dot { background: var(--ib-accent); }
.px-haptic:focus-visible { outline: 2px solid var(--ib-accent); outline-offset: 3px; }

/* --------------------------------------------------------------------------
   C.3  The equal-fall scene, Hadley-Apennine, 2 August 1971
   /space drives a rover across a crater with the scroll position and
   /mathematics closes a chord onto a tangent. This drops a hammer and a
   feather down the panel together, laying a strobe mark every equal slice of
   time. Same contract as both: position is a pure function of where the panel
   sits in the viewport, so scrolling back up unmakes it exactly and there is
   no state to get out of sync.
   -------------------------------------------------------------------------- */
.px-fall-stage { position: relative; z-index: 2; margin-top: 2.5rem; }
/* The scene keeps ONE viewBox for its whole life. The element box comes from
   aspect-ratio, so it is reserved before a byte of script runs, which is the
   difference between a crop and a layout shift. */
.px-fall-svg { display: block; width: 100%; height: auto; aspect-ratio: 1200 / 560; }
/* On a phone the 1200-unit scene would render as a 180 px strip. physics.js
   swaps in a narrower viewBox over the part that is doing the work; this
   reserves the taller box BEFORE a byte of script runs, so it is a crop rather
   than a layout shift. */
@media (max-width: 760px) { .px-fall-svg { aspect-ratio: 720 / 620; } }

.px-fall-caption {
  display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; align-items: baseline;
  font-family: var(--ib-font-mono); font-size: .74rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ib-ink-muted); padding-bottom: 1.25rem;
}
.px-fall-caption b { color: var(--ib-accent); font-weight: 500; }

.px-fall-svg .ground    { stroke: rgba(242,239,232,.42); stroke-width: 2; }
.px-fall-svg .regolith  { fill: rgba(242,239,232,.05); }
.px-fall-svg .strobe    { stroke: rgba(217,178,101,.28); stroke-width: 1; stroke-dasharray: 2 6; }
.px-fall-svg .ghost     { fill: rgba(242,239,232,.16); }
.px-fall-svg .ghost-f   { stroke: rgba(242,239,232,.20); fill: none; stroke-width: 2; }
.px-fall-svg .obj       { fill: var(--ib-accent); }
.px-fall-svg .obj-f     { stroke: var(--ib-accent); fill: none; stroke-width: 2.6; stroke-linecap: round; }
.px-fall-svg .gap-label { font-family: var(--ib-font-mono); font-size: 15px; fill: rgba(217,178,101,.75); text-anchor: middle; }
.px-fall-svg .obj-label { font-family: var(--ib-font-mono); font-size: 15px; fill: rgba(242,239,232,.55); text-anchor: middle; }
.px-fall-svg .rule      { stroke: rgba(242,239,232,.16); stroke-width: 1; }
/* The lander sits behind everything and never moves. */
.px-fall-svg .lm        { stroke: rgba(242,239,232,.30); fill: none; stroke-width: 2; stroke-linejoin: round; }

@media (max-width: 760px) {
  .px-fall-svg .gap-label,
  .px-fall-svg .obj-label { font-size: 22px; }
  .px-fall-svg .obj-f     { stroke-width: 4; }
  .px-fall-svg .ground    { stroke-width: 3; }
}

/* The live numbers. Deliberately large: they are the point of the panel. */
.px-fall-readout {
  display: grid; gap: 1px; margin-top: 2.25rem;
  background: var(--ib-line); border: 1px solid var(--ib-line);
  border-radius: var(--ib-radius); overflow: hidden;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 720px) { .px-fall-readout { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.px-fall-readout > div { background: var(--ib-bg); padding: 1.05rem 1.15rem; }
.px-fall-readout b {
  display: block; font-family: var(--ib-font-mono); font-size: 1.45rem; font-weight: 500;
  color: var(--ib-ink); letter-spacing: -.02em; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.px-fall-readout .is-hot b { color: var(--ib-accent); }
/* No text-transform here: these labels carry v, t and g, and an uppercased
   symbol is a different symbol from the one taught. */
.px-fall-readout span { display: block; margin-top: .4rem; font-size: .74rem; color: var(--ib-ink-muted); letter-spacing: .06em; }

/* --------------------------------------------------------------------------
   C.4  Setting physics without shipping a maths typesetter
   KaTeX costs a 21 kB stylesheet plus a wall of generated spans that nobody
   can edit afterwards. Everything on this page is one line of algebra, which
   the brand's own mono face sets correctly on its own.
   -------------------------------------------------------------------------- */
.px-math {
  font-family: var(--ib-font-mono); font-size: 1.02rem; line-height: 1.9;
  color: var(--ib-ink); background: var(--ib-bg-deep);
  border: 1px solid var(--ib-line); border-left: 2px solid var(--ib-accent);
  border-radius: 0 var(--ib-radius-sm) var(--ib-radius-sm) 0;
  padding: 1rem 1.2rem; margin: 1.1rem 0; overflow-x: auto;
  font-variant-numeric: tabular-nums;
}
.px-math + .px-math { margin-top: .6rem; }
.px-math em { font-style: italic; color: var(--ib-accent); font-weight: 500; }
.px-math small { display: block; font-family: var(--ib-font-sans); font-size: .8rem;
  color: var(--ib-ink-muted); letter-spacing: .02em; margin-top: .45rem; line-height: 1.5; }
.px-in {
  font-family: var(--ib-font-mono); font-size: .96em;
  background: var(--ib-bg-deep); border-radius: 0.25rem; padding: .08em .38em;
  white-space: nowrap;
}
.px-sub { font-size: .7em; vertical-align: -.28em; }
.px-sup { font-size: .7em; vertical-align: .42em; }

/* The three-ages ladder gets more room on this page than on /space, because
   here the working IS the argument. */
.px-ladder { display: grid; gap: 1rem; margin-top: 2.5rem; }
@media (min-width: 1040px) { .px-ladder { grid-template-columns: repeat(3, 1fr); gap: 1.25rem; align-items: start; } }
.px-rung {
  border: 1px solid var(--ib-line); border-radius: var(--ib-radius);
  background: var(--ib-card-bg); padding: 1.7rem 1.75rem 1.8rem;
  position: relative; overflow: hidden;
}
.px-rung::before {
  content: ""; position: absolute; top: 0; left: 0; height: 0.1875rem; width: 100%;
  background: linear-gradient(90deg, var(--ib-accent), var(--ib-gold));
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 1.1s var(--ibe-out);
}
.is-visible .px-rung::before { transform: scaleX(1); }
.is-visible .px-rung:nth-child(2)::before { transition-delay: .12s; }
.is-visible .px-rung:nth-child(3)::before { transition-delay: .24s; }
.px-rung .grade {
  font-family: var(--ib-font-mono); font-size: .76rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--sx-gold-text); font-weight: 500;
}
.px-rung h3 { margin: .55rem 0 .9rem; font-size: 1.18rem; line-height: 1.3; }
.px-rung p { font-size: .95rem; color: var(--ib-ink-soft); }
.px-rung p + p { margin-top: .8rem; }
.px-rung .px-rung-out {
  margin-top: 1.4rem; padding-top: 1.1rem; border-top: 1px solid var(--ib-line);
  font-size: .9rem; color: var(--ib-ink-soft);
}
.px-rung .px-rung-out b {
  display: block; margin-bottom: .4rem; font-family: var(--ib-font-mono);
  font-size: .74rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--sx-accent-text); font-weight: 700;
}

/* --------------------------------------------------------------------------
   C.5  The pendulum interactive
   The counterpart to the rocket equation on /space and the growth bars on
   /mathematics, and it makes a sharper point than either: drag the mass and
   nothing happens. A parent who has just dragged a slider through a factor of
   fifty in mass and watched the period sit still has understood something
   about physics that a paragraph cannot deliver. It reuses the .sx-slider,
   .sx-readout and .sx-verdict furniture; only the picture is new.
   -------------------------------------------------------------------------- */
.px-pend-vis { display: grid; gap: 1.75rem; align-items: start; }
/* Same shape as the rocket stack on /space: a narrow picture column beside the
   numbers. NOT .sx-vehicle, which pins its first column at 78px for a fuel
   tank and would crush a two-metre pendulum into a matchstick. */
@media (min-width: 520px) { .px-pend-vis { grid-template-columns: 9.375rem 1fr; gap: 1.75rem; } }
.px-pend-svg { display: block; width: 100%; height: auto; aspect-ratio: 200 / 360; }
.px-pend-svg .rig    { stroke: rgba(242,239,232,.35); stroke-width: 4; stroke-linecap: round; }
.px-pend-svg .string { stroke: rgba(242,239,232,.72); stroke-width: 1.6; }
.px-pend-svg .arc    { stroke: rgba(242,239,232,.16); stroke-width: 1; stroke-dasharray: 3 5; fill: none; }
.px-pend-svg .bob    { fill: var(--ib-accent); }
.px-pend-svg .bob-ring { fill: none; stroke: rgba(232,132,94,.35); stroke-width: 1; }
/* The bob's radius is written by physics.js from the mass slider, purely so the
   eye has something to hold on to while the period refuses to move.

   The swing is a CSS animation, not a JS loop. The angle of an ideal pendulum
   is θ₀·cos(ωt), and an ease-in-out sine is exactly that curve, so the browser
   runs the whole thing on the compositor for nothing — and it pauses off
   screen and under reduced motion without a line of extra code. */
.px-pend-svg { --px-th: 20deg; --px-dur: 1s; }
.px-swing {
  transform-box: view-box; transform-origin: 100px 24px;
  animation: px-swing var(--px-dur) cubic-bezier(.37, 0, .63, 1) infinite alternate;
}
@keyframes px-swing {
  from { transform: rotate(calc(var(--px-th) * -1)); }
  to   { transform: rotate(var(--px-th)); }
}
.sx-void:not(.is-onscreen) .px-swing { animation-play-state: paused; }

/* --------------------------------------------------------------------------
   C.6  Boards, examinations, and the syllabus map
   The chip row is the same object as the employer row on /space. The map
   under it is new, and it is the section this page was asked for: what is
   actually covered, board by board, in the awarding bodies' own topic names.
   -------------------------------------------------------------------------- */
.px-boards { margin-top: 2rem; display: flex; flex-wrap: wrap; gap: .55rem; }
.px-boards span {
  font-family: var(--ib-font-mono); font-size: .76rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ib-ink-soft);
  border: 1px solid var(--ib-line); border-radius: 62.4375rem; padding: .42rem .9rem;
  transition: border-color var(--ib-dur-2), color var(--ib-dur-2);
}
.px-boards span:hover { border-color: var(--ib-accent); color: var(--ib-accent); }

.px-syllabus { display: grid; gap: 1rem; margin-top: 2rem; }
@media (min-width: 760px)  { .px-syllabus { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1140px) { .px-syllabus { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.px-board {
  border: 1px solid var(--ib-line); border-radius: var(--ib-radius);
  background: var(--ib-card-bg); padding: 1.5rem 1.6rem 1.6rem;
}
.px-board > .code {
  font-family: var(--ib-font-mono); font-size: .72rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--sx-gold-text); font-weight: 500;
}
.px-board h4 { margin: .5rem 0 .2rem; font-size: 1.05rem; line-height: 1.3; }
.px-board > .exam {
  font-size: .82rem; color: var(--ib-ink-muted); line-height: 1.5;
  padding-bottom: .95rem; margin-bottom: .95rem; border-bottom: 1px solid var(--ib-line);
}
.px-board ol, .px-board ul {
  list-style: none; margin: 0; padding: 0;
  font-size: .88rem; color: var(--ib-ink-soft); line-height: 1.5;
}
.px-board li { position: relative; padding-left: 1.6rem; }
.px-board li + li { margin-top: .5rem; }
.px-board ol { counter-reset: px-topic; }
.px-board ol > li::before {
  counter-increment: px-topic; content: counter(px-topic);
  position: absolute; left: 0; top: .05rem;
  font-family: var(--ib-font-mono); font-size: .74rem;
  color: var(--sx-accent-text); font-variant-numeric: tabular-nums;
}
.px-board ul > li::before {
  content: ""; position: absolute; left: .35rem; top: .58em;
  width: 0.3125rem; height: 0.3125rem; border-radius: 50%; background: var(--ib-line-strong);
}
.px-board .hl { color: var(--sx-accent-text); font-weight: 600; }

/* --------------------------------------------------------------------------
   C.7  The plan, and the fact that it is written for one student
   A bordered ladder rather than another card grid, because this is a sequence
   and the page already has three card grids.
   -------------------------------------------------------------------------- */
.px-plan { display: grid; gap: 0; margin-top: 2.25rem; border: 1px solid var(--ib-line); border-radius: var(--ib-radius); overflow: hidden; }
@media (min-width: 960px) { .px-plan { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.px-plan-step { padding: 1.6rem 1.7rem 1.7rem; background: var(--ib-card-bg); position: relative; }
.px-plan-step + .px-plan-step { border-top: 1px solid var(--ib-line); }
@media (min-width: 960px) {
  .px-plan-step + .px-plan-step { border-top: 0; border-left: 1px solid var(--ib-line); }
}
.px-plan-step > b {
  display: block; font-family: var(--ib-font-mono); font-size: .72rem;
  letter-spacing: .18em; text-transform: uppercase; color: var(--sx-accent-text);
  margin-bottom: .8rem;
}
.px-plan-step h4 { margin: 0 0 .55rem; font-size: 1.02rem; line-height: 1.3; }
.px-plan-step p { font-size: .9rem; color: var(--ib-ink-soft); line-height: 1.6; }

/* --------------------------------------------------------------------------
   C.8  The branch card, on top of .sx-field
   Only two differences from /space: the icon tile carries a glyph as often as
   a pictogram, and a branch carries a one-line "what it is for" under the
   syllabus, which /space handles in its overlap note instead.
   -------------------------------------------------------------------------- */
.sx-field .px-branch-for {
  margin-top: 1.2rem; padding-top: .95rem; border-top: 1px solid var(--ib-line);
  font-size: .84rem; color: var(--ib-ink-muted); line-height: 1.5;
}
.sx-field .px-branch-for b {
  color: var(--sx-accent-text); font-weight: 600; display: block;
  font-family: var(--ib-font-mono); font-size: .74rem; letter-spacing: .14em;
  text-transform: uppercase; margin-bottom: .35rem;
}
.px-glyph {
  font-family: var(--ib-font-mono); font-size: .86rem; font-weight: 500;
  line-height: 1; letter-spacing: -.03em; white-space: nowrap;
}

/* --------------------------------------------------------------------------
   C.9  Motion guards for everything PART C adds
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .px-lines { animation: none; }
  /* Parked at one extreme, which is the clearest static state a pendulum has,
     and the readouts beside it are unaffected. */
  .px-swing { animation: none; transform: rotate(calc(var(--px-th) * -1)); }
  /* the cannonball stops of its own accord; module 7b draws the closed orbit
     once and never starts a loop, and the fall scene is pinned by physics.js
     at a readable moment with its numbers still correct */
}

@media print {
  .px-lines { display: none !important; }
  .px-math { border-color: #999; }
  .px-board { break-inside: avoid; }
}

@media (forced-colors: active) {
  .px-rung, .px-math, .px-board, .px-plan-step,
  .px-fall-readout > div { border: 1px solid CanvasText; }
  /* Every stroke collapses to CanvasText here, and the whole panel is "watch
     two objects fall together". Weight and dash are the only channels left. */
  .px-fall-svg .obj, .px-fall-svg .obj-f { stroke-width: 4; }
  .px-fall-svg .ghost, .px-fall-svg .ghost-f { stroke-width: 1; stroke-dasharray: 3 4; }
  .px-fall-svg .strobe { display: none; }
}


/* ============================================================
   Insight Bay — mobile footer density fix   (2026-08-09)
   Scoped to <= 767px. Desktop untouched.
   The footer link columns are plain <a> blocks inside
   .ib-footer-grid > div, so this targets that structure:
   every link group after the brand column flows into two
   newspaper columns (reading order preserved, top to bottom
   then across) and every link keeps a 44px tap target.
   No font-size, colour or copy is changed.
   Rollback: delete this block.
   ============================================================ */
@media (max-width: 767px) {
  .ib-footer { padding-top: 3rem; }

  .ib-footer-grid { row-gap: 1.5rem; }

  /* Skip the first child: that is the brand / bio / social column. */
  .ib-footer-grid > div + div {
    columns: 2;
    column-gap: 1.125rem;
  }

  .ib-footer-grid > div + div > h4 {
    column-span: all;
    -webkit-column-span: all;
    margin-bottom: .45rem;
  }

  .ib-footer-grid > div + div > a {
    display: flex;
    align-items: center;
    min-height: 2.75rem;
    line-height: 1.3;
    padding: .25rem 0.375rem .25rem 0;
    overflow-wrap: anywhere;
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    page-break-inside: avoid;
  }
}

/* Skip link: off-screen until focused (same rule as styles.css;
   this page does not load styles.css, so it was showing). */
.ib-skip{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden;z-index:2000}
.ib-skip:focus,.ib-skip:focus-visible{left:.75rem;top:.75rem;width:auto;height:auto;overflow:visible;padding:.6rem 1.05rem;border-radius:.5rem;background:var(--ib-bg-deep,#12141a);color:var(--ib-ink,#f5f1eb);font-weight:600;text-decoration:none;outline:2px solid var(--ib-accent,#c2673c);outline-offset:2px}


/* ============================================================
   Wide screens (added 21 Sep 2026). Nothing changes below 1280px.
   Above it the layout grows with the window instead of sitting in
   a fixed 1180px column: the container keeps a slim outer margin
   and the whole type and spacing scale (all in rem) rises gently,
   from 16px at 1280 to 20px at 1920, capped at 22px, so every
   section keeps its proportions.
   ============================================================ */
@media (min-width: 1280px) {
  html { font-size: clamp(100%, calc(50% + 0.625vw), 137.5%); }
  .ib-container,
  .sx-wide { max-width: min(calc(84.375vw + 100px), 92rem); }
}


/* ============================================================
   Brand mark (21 Sep 2026). The rounded square and the slanted
   "i" follow the master logo artwork exactly: on its 800 unit
   grid the corner radius is 175, the dot is r 67.5 centred at
   (416.25, 218.75) and the stem is a 117.5 wide pill skewed by
   8 degrees. The box keeps the site accent colour. The letter in
   the markup stays for screen readers but is not painted.
   ============================================================ */
.ib-logo-mark {
  border-radius: 21.875%; color: transparent;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 800' fill='white'%3E%3Ccircle cx='416.25' cy='218.75' r='67.5'/%3E%3Crect x='391.25' y='337.5' width='117.5' height='306.25' rx='58.75' transform='skewX(-8)'/%3E%3C/svg%3E");
  background-position: center; background-size: 100% 100%; background-repeat: no-repeat;
}
