@layer tokens, base, layout, components, sections, utilities;

/* ── tokens.css ─────────────────────────── */
/* ============================================================================
   TOKENS — the only file in this codebase where a raw value is allowed.
   Every color, space, size, radius, weight and duration is declared here and
   nowhere else. Change a value here and all eleven pages change together.
   Approved: docs/design/palette-proposal.html
   ========================================================================= */

@layer tokens {
:root {

  /* ── 1. CORE ───────────────────────────────────────────────────────────
     Sampled from the logo artwork. These four are the brand. Not negotiable. */
  --c-ink:            #122C4B;   /* headlines, dark section grounds          */
  --c-navy:           #1A3A62;   /* surfaces inside dark sections, tags      */
  --c-blue:           #0E6594;   /* links, active states                     */
  --c-azure:          #1578B6;   /* accents, diagram connectors, graphics    */
  --c-azure-on-dark:  #7FBCE4;   /* azure lifted for the dark ground (6.9:1) */
  --c-azure-text:     #136EA7;   /* azure as small text — 5.0:1 on every light
                                    ground. Graphics may use --c-azure; text
                                    never does.                               */

  /* ── 2. GROUNDS ────────────────────────────────────────────────────────
     Four page grounds. Which one a section gets is a meaning decision, not a
     visual one — see the ground rule in docs/DESIGN-SYSTEM.md. Never place
     two sections with the same ground next to each other. */
  --g-paper:          #FFFFFF;   /* default                                  */
  --g-sand:           #FBF7F2;   /* warm — human, narrative, company         */
  --g-mist:           #F2F6FA;   /* cold — technical, precise, engineered    */
  --g-ink:            var(--c-ink); /* dark — emphasis, max two or three /page */

  /* Surfaces that sit on top of a ground */
  --g-card:           #FFFFFF;
  --g-card-on-dark:   #1B3A63;
  --g-stone:          #F1EBE3;   /* deeper warm tint, quiet panels           */

  /* ── 3. ACTION — amber. The only warm saturated color on the page, so the
     eye finds it without hunting. Actions only: primary buttons, the header
     CTA, the active nav item, the one link that matters most in a section.
     Never a heading. Never a background band. */
  --a-amber:          #D98324;   /* the action colour                        */
  --a-amber-hover:    #E19A4C;   /* hover brightens rather than darkens, so the
                                    ink label stays legible (6.0:1)           */
  --a-amber-deep:     #A1611B;   /* amber as text on a light ground (4.95:1)  */
  --a-amber-light:    #E19A4C;   /* amber as text on the dark ground (6.0:1)  */
  --a-amber-ink:      var(--c-ink); /* label on an amber surface: ink at 4.86:1.
                                    White on amber is 2.91:1 and fails AA.    */

  /* ── 4. DOMAIN HUES — one per technology pillar. Carried through the
     pillar's eyebrow, card and diagrams so the four technology pages feel
     distinct while sharing one system. All cool, so warm still means
     "click this". */
  --d-ai:             #1578B6;   /* Advanced AI & Autonomous Intelligence    */
  --d-automation:     #14807C;   /* Intelligent Automation & Orchestration   */
  --d-robotics:       #6152A3;   /* Embodied AI & Robotics                   */
  --d-networks:       #2C4B9B;   /* Beyond-5G/6G & Advanced Networks         */

  /* Tints of each, for cards and diagram fills on light grounds */
  --d-ai-tint:         #E7F1F8;
  --d-ai-tint-deep:    #D6E7F4;  /* the same tint, one step down, for hover  */
  --d-automation-tint: #E4F1F0;
  --d-robotics-tint:   #EDEAF5;
  --d-networks-tint:   #E7EBF6;

  /* ── 5. SEMANTIC — meaning inside diagrams only. Never page chrome. */
  --a-amber-tint:     #F7EBDA;   /* amber at surface strength, for labels    */

  /* ── 5. SEMANTIC — meaning inside diagrams only. Never page chrome. */
  --s-valid:          #2E7D57;   /* an approved, validated path              */
  --s-blocked:        #C25E4E;   /* a rejected action, an exception          */
  --s-human:          var(--a-amber); /* the human in the loop              */

  /* ── TEXT ─────────────────────────────────────────────────────────────── */
  --t-strong:         var(--c-ink);
  --t-body:           #4A5A6E;
  --t-muted:          #627289;   /* 4.5:1 on every light ground, mist included */
  --t-on-dark:        #FFFFFF;
  --t-on-dark-body:   #9CB4CE;
  --t-on-dark-muted:  #7D94AE;   /* 4.5:1 on ink                             */

  /* ── DIAGRAM SURFACES ──────────────────────────────────────────────────
     Diagrams appear on light and dark grounds alike. Reading these four
     instead of the ground-specific colours is what lets the same diagram
     work in both places — the dark override lives in layout.css. */
  --dg-surface:      #FFFFFF;
  --dg-surface-soft: #F2F6FA;
  --dg-line:         #D9DEE5;
  --dg-text:         var(--t-strong);
  --dg-text-muted:   var(--t-muted);

  /* The same four, as they must appear inside a dark band. layout.css swaps
     the names over; the values live here like every other value. */
  --dg-surface-on-dark:      #1B3A63;
  --dg-surface-soft-on-dark: #16314F;
  --dg-line-on-dark:         rgba(255, 255, 255, .22);
  --dg-text-on-dark:         #FFFFFF;

  /* Surfaces used by the dark data illustrations */
  --dg-panel-on-dark:        #0E2743;

  /* ── PRINT ─────────────────────────────────────────────────────────────
     Browsers drop background colours when printing, so anything that relied
     on a ground for contrast is re-stated in ink on white. */
  --p-paper:      #FFFFFF;
  --p-ink:        var(--c-ink);
  --p-body:       #333333;
  --p-muted:      #555555;
  --p-line:       #CCCCCC;

  /* ── LINES ────────────────────────────────────────────────────────────── */
  --line:             #E4E7EB;
  --line-warm:        #EBE3D9;
  --line-on-dark:     rgba(255,255,255,.14);

  /* ── TYPE ─────────────────────────────────────────────────────────────
     One family, self-hosted. Fluid sizes so a 14" laptop and a 27" display
     both read correctly without a breakpoint for every step. */
  --f-sans: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
            Helvetica, Arial, sans-serif;
  --f-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --fs-eyebrow:  0.78rem;
  --fs-small:    0.9rem;
  --fs-body:     1.0625rem;
  --fs-lead:     clamp(1.125rem, 0.98rem + 0.6vw,  1.375rem);
  --fs-h4:       clamp(1.0625rem, 1rem + 0.3vw,   1.25rem);
  --fs-h3:       clamp(1.3rem,  1.15rem + 0.7vw,  1.6rem);
  --fs-h2:       clamp(1.85rem, 1.4rem + 2.1vw,   3.05rem);
  --fs-h1:       clamp(2.4rem,  1.6rem + 3.6vw,   4.6rem);

  --fw-normal:   400;
  --fw-medium:   500;
  --fw-semi:     600;

  --lh-tight:    1.06;
  --lh-heading:  1.16;
  --lh-body:     1.62;

  --ls-h1:      -0.042em;
  --ls-h2:      -0.036em;
  --ls-h3:      -0.028em;
  --ls-body:    -0.005em;
  --ls-eyebrow:  0.09em;

  /* ── SPACE — one scale, used everywhere. No arbitrary pixel values. */
  --sp-1:  0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;  --sp-4: 1rem;
  --sp-5:  1.5rem;   --sp-6: 2rem;     --sp-7: 2.75rem;  --sp-8: 3.5rem;
  --sp-9:  4.5rem;   --sp-10: 6rem;    --sp-11: 8rem;

  /* Vertical rhythm of a section. Roughly half what it was: the previous
     values were scaled to fill a large screen, which left the page reading
     as mostly empty rather than generous. */
  --sp-section:    clamp(2.25rem, 1.5rem + 2.6vw, 4rem);
  --sp-section-sm: clamp(1.75rem, 1.25rem + 1.6vw, 2.75rem);

  /* ── CONTAINERS — three widths, not one. This is what stops the page
     feeling centre-locked on a wide monitor while keeping prose readable.  */
  --w-read:     68ch;     /* body prose — never wider, at any screen size   */
  --w-content:  75rem;    /* standard section content                       */
  --w-wide:     100rem;   /* diagrams, imagery, galleries                   */
  --gutter:     clamp(1.25rem, 0.5rem + 3vw, 3rem);

  /* ── RADIUS ───────────────────────────────────────────────────────────── */
  --r-sm: 8px;  --r-md: 14px;  --r-lg: 22px;  --r-pill: 999px;

  /* ── ELEVATION — restrained. Depth comes from ground changes, not shadow. */
  --el-1: 0 1px 2px rgba(18,44,75,.05);
  --el-2: 0 14px 40px rgba(18,44,75,.13);

  /* ── MOTION ───────────────────────────────────────────────────────────── */
  --dur-fast:  .18s;
  --dur-base:  .26s;
  --dur-slow:  .5s;
  --ease:      cubic-bezier(.4, 0, .2, 1);
  --ease-out:  cubic-bezier(0, 0, .2, 1);

  /* ── LAYERS ───────────────────────────────────────────────────────────── */
  --z-header: 100;  --z-menu: 200;
}
}

/* ── base.css ─────────────────────────── */
/* ============================================================================
   BASE — reset and element defaults. Reads tokens only; declares no values.
   ========================================================================= */

@layer base {

/* Self-hosted so the site has no third-party request. Also keeps the site
   clean for European visitors, where hotlinking Google Fonts has been found
   to breach GDPR. Variable font: one file covers weights 400–700. */
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../assets/fonts/instrument-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../assets/fonts/instrument-sans-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* clears the sticky header when jumping to an anchor */
  scroll-padding-top: 6rem;
  /* clip, not hidden: `hidden` on an ancestor turns it into a scroll
     container and silently breaks the sticky header. This has to be set on
     html as well as body, because body alone does not clip the page's own
     scroll area. */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--g-paper);
  color: var(--t-strong);
  font-family: var(--f-sans);
  font-size: var(--fs-body);
  font-weight: var(--fw-normal);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* the page itself never scrolls sideways; wide children scroll internally */
  overflow-x: clip;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-weight: var(--fw-semi);
  line-height: var(--lh-heading);
  color: inherit;
  text-wrap: balance;
}
h1 { font-size: var(--fs-h1); line-height: var(--lh-tight); letter-spacing: var(--ls-h1); }
h2 { font-size: var(--fs-h2); letter-spacing: var(--ls-h2); }
h3 { font-size: var(--fs-h3); letter-spacing: var(--ls-h3); }
h4 { font-size: var(--fs-h4); letter-spacing: var(--ls-h3); }

p { margin: 0 0 1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--c-blue); text-decoration-thickness: 1px; text-underline-offset: .2em; }
a:hover { color: var(--c-ink); }

ul, ol { margin: 0; padding: 0; }
li { list-style: none; }

img, svg, video { display: block; max-width: 100%; height: auto; }

button, input, select, textarea { font: inherit; color: inherit; }

code { font-family: var(--f-mono); font-size: .88em; letter-spacing: 0; }

/* Focus: always visible, never removed. Keyboard users must see where they are. */
:focus-visible {
  outline: 2px solid var(--a-amber);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* Skip link — first stop for a keyboard or screen-reader visitor */
.skip {
  position: absolute; left: var(--sp-4); top: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  background: var(--c-ink); color: var(--t-on-dark);
  border-radius: var(--r-pill); font-weight: var(--fw-semi);
  z-index: calc(var(--z-menu) + 1);
  transform: translateY(-200%);
}
.skip:focus { transform: none; color: var(--t-on-dark); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

}

/* ── layout.css ─────────────────────────── */
/* ============================================================================
   LAYOUT — the page shell, the container system, and the ground system.
   Answers the CEO's wide-monitor note: three widths instead of one, so text
   stays readable while visuals and emphasis bands fill a large display.
   ========================================================================= */

@layer layout {

/* ── Containers ──────────────────────────────────────────────────────────
   Three widths. Prose never exceeds --w-read regardless of monitor size,
   because a 140-character line is unreadable on any screen. */

.l-content,
.l-wide,
.l-read {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.l-content { max-width: var(--w-content); }
.l-wide    { max-width: var(--w-wide); }
.l-read    { max-width: calc(var(--w-read) + var(--gutter) * 2); }

/* Prose inside a wider container */
.l-prose { max-width: var(--w-read); }

/* Full-bleed: escape any container and run edge to edge. Used by dark bands
   and hero visuals so a wide monitor is filled rather than framed. */
.l-bleed {
  width: 100vw;
  margin-left: 50%;
  transform: translateX(-50%);
}

/* ── Sections and their grounds ─────────────────────────────────────────
   A section's ground is a meaning decision, not a visual one:

     paper  default — the page speaks normally
     sand   warm  — human, narrative, company: DNA, About, ecosystem, process
     mist   cold  — technical, precise: components, standards, specifications
     ink    dark  — emphasis. Two or three per page at most, never the home hero

   Two sections with the same ground are never placed next to each other. */

.l-section {
  padding-block: var(--sp-section);
  position: relative;
}
.l-section--sm { padding-block: var(--sp-section-sm); }

.l-section--paper { background: var(--g-paper); }
.l-section--sand  { background: var(--g-sand); }
.l-section--mist  { background: var(--g-mist); }

.l-section--ink {
  background: var(--g-ink);
  color: var(--t-on-dark);
}
.l-section--ink :is(h1,h2,h3,h4,h5,h6) { color: var(--t-on-dark); }
.l-section--ink p { color: var(--t-on-dark-body); }
.l-section--ink a:not([class]) { color: var(--a-amber-light); }

/* Diagrams inside a dark band re-point their surface tokens rather than
   being redrawn. Without this a diagram built for white paper floats on the
   navy as an unreadable light card. */
.l-section--ink {
  --dg-surface:      var(--dg-surface-on-dark);
  --dg-surface-soft: var(--dg-surface-soft-on-dark);
  --dg-line:         var(--dg-line-on-dark);
  --dg-text:         var(--dg-text-on-dark);
  --dg-text-muted:   var(--t-on-dark-muted);
}

/* ── Section heading block ─────────────────────────────────────────────── */
/* The block is not capped: a heading was being forced to the paragraph's
   reading width and wrapping two or three times when it would fit on one
   line. The paragraph keeps the reading width; the heading gets its own,
   wider cap. */
.l-head { max-width: none; margin-bottom: var(--sp-7); }
.l-head :is(h1, h2) { max-width: 46ch; }
.l-head p { max-width: 46rem; }
/* Centring the block is not enough now that the heading and the paragraph
   carry their own widths: each has to be centred within it, or the text sits
   centred inside a box that is itself left-aligned. */
.l-head--center { text-align: center; }
.l-head--center :is(h1, h2),
.l-head--center p { margin-inline: auto; }
.l-head > * + * { margin-top: var(--sp-3); }
.l-head p { font-size: var(--fs-lead); color: var(--t-body); line-height: 1.5; }
.l-section--ink .l-head p { color: var(--t-on-dark-body); }

/* ── Grids ───────────────────────────────────────────────────────────────
   Auto-fitting so a 14" laptop and a 27" display both fill sensibly without
   a media query per breakpoint. */
.l-grid { display: grid; gap: var(--sp-5); }
.l-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
.l-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }
.l-grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); }

/* Prose beside a figure — the explainer layout. Alternates side by side. */
.l-split {
  display: grid;
  gap: var(--sp-6) var(--sp-8);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  align-items: center;
}
.l-split--figure-first > :first-child { order: 2; }
@media (max-width: 60rem) {
  .l-split--figure-first > :first-child { order: 0; }
}

/* ── Page shell ──────────────────────────────────────────────────────── */
.l-page { display: flex; flex-direction: column; min-height: 100vh; }
.l-main { flex: 1 0 auto; }

/* A wide element that must not force the page sideways scrolls inside itself */
.l-scroll-x { overflow-x: auto; }

}

/* ── components.css ─────────────────────────── */
/* ============================================================================
   COMPONENTS — shared visual parts. A section never re-implements one of
   these locally; it uses them. Reads tokens only.
   ========================================================================= */

@layer components {

/* ── Eyebrow ─────────────────────────────────────────────────────────────
   Small uppercase label above a heading. Carries the domain hue on the
   technology pages, which is how each pillar reads as its own without
   any change to the layout. */
.c-eyebrow {
  display: block;
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-semi);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--c-azure-text);
}
.l-section--ink .c-eyebrow { color: var(--c-azure-on-dark); }
.c-eyebrow--ai         { color: var(--d-ai); }
.c-eyebrow--automation { color: var(--d-automation); }
.c-eyebrow--robotics   { color: var(--d-robotics); }
.c-eyebrow--networks   { color: var(--d-networks); }

/* ── Buttons ─────────────────────────────────────────────────────────────
   Copper is the action color and appears nowhere else. Two or three per page
   at most — its power comes from being rare. */
.c-btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-6);
  border: 0; border-radius: var(--r-pill);
  font-size: var(--fs-body); font-weight: var(--fw-semi);
  letter-spacing: -.01em; text-decoration: none; cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}

/* Primary — the single most important action in view */
.c-btn--primary { background: var(--a-amber); color: var(--a-amber-ink); }
.c-btn--primary:hover { background: var(--a-amber-hover); color: var(--a-amber-ink); }
.l-section--ink .c-btn--primary:hover { background: var(--a-amber-hover); color: var(--a-amber-ink); }

/* Secondary — an action that is available but not the point */
.c-btn--secondary { background: var(--d-ai-tint); color: var(--c-blue); }
.c-btn--secondary:hover { background: var(--d-ai-tint-deep); color: var(--c-ink); }
.l-section--ink .c-btn--secondary { background: rgba(255,255,255,.1); color: #fff; }
.l-section--ink .c-btn--secondary:hover { background: rgba(255,255,255,.18); }

/* Quiet — a text action, no container */
.c-btn--quiet { padding-inline: 0; background: none; color: var(--c-blue); }
.c-btn--quiet:hover { background: none; color: var(--c-ink); }
.l-section--ink .c-btn--quiet { color: var(--a-amber-light); }

/* ── Arrow link ──────────────────────────────────────────────────────── */
.c-link {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-small); font-weight: var(--fw-semi);
  color: var(--c-blue); text-decoration: none;
  transition: gap var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.c-link::after { content: "→"; transition: transform var(--dur-fast) var(--ease); }
.c-link:hover { gap: var(--sp-3); color: var(--c-ink); }
.l-section--ink .c-link { color: var(--a-amber-light); }
.l-section--ink .c-link:hover { color: #fff; }

/* ── Button row ──────────────────────────────────────────────────────── */
.c-actions { display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: center; }
.c-actions--center { justify-content: center; }

/* ── Maturity label ──────────────────────────────────────────────────────
   Blueprint §18: distinguishes demonstrated expertise from active R&D from
   an initiative, so ambition never reads as overclaiming. */
.c-label {
  display: inline-block;
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-eyebrow); font-weight: var(--fw-semi);
  letter-spacing: .04em; text-transform: uppercase;
}
.c-label--expertise  { background: var(--d-ai-tint);        color: var(--c-blue); }
.c-label--active     { background: var(--d-automation-tint); color: var(--d-automation); }
.c-label--initiative { background: var(--a-amber-tint);                  color: var(--a-amber-deep); }

/* ── Tag ─────────────────────────────────────────────────────────────── */
.c-tag {
  display: inline-block;
  font-size: var(--fs-small); color: var(--t-muted);
}
.c-tags { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); }

/* ── Card ────────────────────────────────────────────────────────────────
   Used sparingly. Most sections separate content with space and ground
   changes rather than boxes — a page of identical cards is what the drafts
   were rejected for. */
.c-card {
  display: block;
  padding: var(--sp-7);
  background: var(--g-card);
  border-radius: var(--r-lg);
  box-shadow: var(--el-1);
  text-decoration: none; color: inherit;
  transition: transform var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
a.c-card:hover { transform: translateY(-4px); box-shadow: var(--el-2); }
.l-section--ink .c-card { background: var(--g-card-on-dark); box-shadow: none; }

/* ── Bulleted list with a dot in the domain hue ─────────────────────────── */
.c-list li {
  position: relative;
  padding-left: var(--sp-5);
  font-size: var(--fs-small);
  color: var(--t-body);
  line-height: 1.9;
}
.c-list li::before {
  content: ""; position: absolute; left: 0; top: .85em;
  width: 5px; height: 5px; border-radius: 50%;
  background: currentColor; opacity: .45;
}

/* ── Rule ────────────────────────────────────────────────────────────── */
.c-rule { height: 1px; border: 0; background: var(--line); margin: 0; }
.l-section--ink .c-rule { background: var(--line-on-dark); }

/* ── Placeholder ──────────────────────────────────────────────────────────
   Marks content the client still has to supply. Deliberately conspicuous:
   an amber dashed outline and a reference code, so nothing can be missed and
   so a specific one can be named in an email. Every placeholder on the site
   is listed by scripts/verify.sh.

   These must all be gone before the site goes live on elyonx.com. */
.c-placeholder {
  position: relative;
  display: flex; flex-direction: column; justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-5);
  border: 2px dashed var(--a-amber);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--a-amber) 6%, transparent);
}
.c-placeholder__tag {
  align-self: flex-start;
  padding: 2px var(--sp-2); border-radius: var(--r-sm);
  background: var(--a-amber); color: var(--a-amber-ink);
  font-size: 10.5px; font-weight: var(--fw-semi);
  letter-spacing: .08em; text-transform: uppercase;
}
.c-placeholder__what {
  font-size: var(--fs-small); font-weight: var(--fw-medium); color: var(--t-strong);
}
.c-placeholder__note { font-size: var(--fs-eyebrow); color: var(--t-body); line-height: 1.5; }
.c-placeholder__ref {
  font-family: var(--f-mono); font-size: 10.5px; color: var(--a-amber-deep);
}
.l-section--ink .c-placeholder__what { color: var(--t-on-dark); }
.l-section--ink .c-placeholder__note { color: var(--t-on-dark-body); }
.l-section--ink .c-placeholder__ref  { color: var(--a-amber-light); }

/* A placeholder standing in for an image keeps that image's proportions, so
   the surrounding layout does not shift when the real file arrives. */
/* Inside the marquee the tile has to stay logo-sized, so this variant drops
   the note and keeps only the name and the reference. */
.c-placeholder--logo { padding: var(--sp-3); align-items: center; text-align: center; gap: var(--sp-1); }
.c-placeholder--logo .c-placeholder__tag { display: none; }
.c-placeholder--logo .c-placeholder__what { font-size: var(--fs-eyebrow); line-height: 1.3; }
.c-placeholder--logo .c-placeholder__what { font-size: var(--fs-eyebrow); }

/* ── Figure ──────────────────────────────────────────────────────────────
   Diagrams keep their aspect ratio and scroll inside themselves on a narrow
   screen rather than forcing the page sideways. */
.c-figure { margin: 0; }
.c-figure svg { width: 100%; height: auto; }
.c-figure figcaption {
  margin-top: var(--sp-4);
  font-size: var(--fs-small); color: var(--t-muted);
}

}

/* ── applications.css ─────────────────────────── */
/* ── Applications ─────────────────────────────────────────────────────── */
@layer sections {

.s-applications__list {
  display: grid; gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}
.s-applications__item {
  display: flex; align-items: baseline; gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-6) var(--sp-4) 0;
  border-bottom: 1px solid var(--line-on-dark);
}
.s-applications__n {
  font-family: var(--f-mono); font-size: var(--fs-small);
  color: var(--c-azure-on-dark); flex-shrink: 0;
}
.s-applications__text { color: var(--t-on-dark); font-weight: var(--fw-medium); }

}

/* ── capability-points.css ─────────────────────────── */
/* ── Capability points ────────────────────────────────────────────────────
   Four kinds of work, each with a mark that shows the shape of that work
   rather than a generic icon. */
@layer sections {

.s-caps__list {
  display: grid; gap: var(--sp-7) var(--sp-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  grid-auto-rows: auto auto auto;
}
.s-caps__item {
  display: grid; grid-template-rows: subgrid; grid-row: span 3;
  gap: var(--sp-3); align-content: start;
}
@supports not (grid-template-rows: subgrid) { .s-caps__item { display: block; } }

.s-caps__mark { display: block; width: 4.5rem; }
.s-caps__name { font-size: var(--fs-h4); margin: 0; }
.s-caps__text { font-size: var(--fs-small); color: var(--t-body); line-height: 1.6; margin: 0; }

/* ── marks ────────────────────────────────────────────────────────────── */
.s-cap { width: 100%; height: auto; }

/* technical: layers inspected by a scan passing down the stack */
.s-cap__layer {
  fill: none; stroke: var(--d-robotics); stroke-width: 2; opacity: .35;
  animation: s-cap-layer 4.5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .4s);
}
@keyframes s-cap-layer { 0%,70%,100% { opacity: .35; } 12%,24% { opacity: 1; } }
.s-cap__scan {
  stroke: var(--a-amber); stroke-width: 2; stroke-linecap: round;
  animation: s-cap-scan 4.5s var(--ease) infinite;
}
@keyframes s-cap-scan {
  0%   { transform: translateY(0);   opacity: 0; }
  10%  { opacity: 1; }
  70%  { transform: translateY(58px); opacity: 1; }
  85%, 100% { transform: translateY(58px); opacity: 0; }
}
.s-cap__probe { fill: var(--d-robotics); opacity: .8; }

/* company: a hub assessed across its parts */
.s-cap__hub   { fill: none; stroke: var(--d-robotics); stroke-width: 2.5; }
.s-cap__spoke { stroke: var(--d-robotics); stroke-width: 1.5; opacity: .3; }
.s-cap__unit  {
  fill: var(--dg-surface); stroke: var(--d-robotics); stroke-width: 2;
  animation: s-cap-unit 5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .5s);
}
@keyframes s-cap-unit { 0%,80%,100% { fill: var(--dg-surface); } 10%,22% { fill: var(--d-robotics); } }

/* market: columns settling, one trend rising above them */
.s-cap__axis { stroke: var(--d-robotics); stroke-width: 1.5; opacity: .35; }
.s-cap__col  {
  fill: var(--d-robotics); opacity: .3;
  transform-box: fill-box; transform-origin: center bottom;
  animation: s-cap-col 5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .22s);
}
@keyframes s-cap-col { 0%,100% { transform: scaleY(1); } 50% { transform: scaleY(.6); } }
.s-cap__trend {
  fill: none; stroke: var(--a-amber); stroke-width: 2.5;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 120; stroke-dashoffset: 120;
  animation: s-cap-trend 5s var(--ease) infinite;
}
@keyframes s-cap-trend { 0% { stroke-dashoffset: 120; } 45%,100% { stroke-dashoffset: 0; } }
.s-cap__peak { fill: var(--a-amber); }

/* growth: two parties meeting, a bond forming between them */
.s-cap__party { fill: none; stroke: var(--d-robotics); stroke-width: 2.5; }
.s-cap__party--a { animation: s-cap-in-a 5s var(--ease) infinite; }
.s-cap__party--b { animation: s-cap-in-b 5s var(--ease) infinite; }
@keyframes s-cap-in-a { 0%,100% { transform: translateX(-6px); } 50% { transform: translateX(0); } }
@keyframes s-cap-in-b { 0%,100% { transform: translateX(6px); }  50% { transform: translateX(0); } }
.s-cap__bond {
  stroke: var(--a-amber); stroke-width: 3; stroke-linecap: round;
  animation: s-cap-bond 5s var(--ease) infinite;
}
@keyframes s-cap-bond { 0%,30%,100% { opacity: 0; } 50%,75% { opacity: 1; } }
.s-cap__seed {
  fill: var(--d-robotics); opacity: .35;
  animation: s-cap-seed 5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .5s);
}
@keyframes s-cap-seed { 0%,60%,100% { opacity: .2; } 78% { opacity: .9; } }

@media (prefers-reduced-motion: reduce) {
  .s-cap__layer, .s-cap__scan, .s-cap__unit, .s-cap__col, .s-cap__trend,
  .s-cap__party, .s-cap__bond, .s-cap__seed { animation: none; }
  .s-cap__scan  { opacity: .6; }
  .s-cap__trend { stroke-dashoffset: 0; }
  .s-cap__bond  { opacity: 1; }
}

}

/* ── chain.css ─────────────────────────── */
/* ── The convergence chain ────────────────────────────────────────────────
   A closed loop, drawn as one: six stages forward, then a feedback arc back
   into intelligence. Three particles run the path on a continuous offset, so
   flow never stops and never restarts visibly.

   Performance: only `offset-distance` and `opacity` animate, both compositor
   friendly, and only three elements are in motion at any time. */
@layer sections {

.s-chain__figure { margin-top: var(--sp-6); min-width: 64rem; }

/* Solid and visible: if the track cannot be seen, the chain is just six
   disconnected circles. */
.s-chain__track { stroke: rgba(127,188,228,.42); stroke-width: 2; }
.s-chain__chevron {
  fill: none; stroke: rgba(127,188,228,.55); stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.s-chain__tip   { fill: rgba(127,188,228,.5); }

.s-chain__feedback {
  fill: none; stroke: rgba(127,188,228,.34); stroke-width: 1.5;
  stroke-dasharray: 5 7; stroke-linecap: round;
  animation: s-chain-return 3.2s linear infinite;
}
@keyframes s-chain-return { to { stroke-dashoffset: -24; } }

.s-chain__feedback-label {
  fill: var(--t-on-dark-muted); font-family: var(--f-sans);
  font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase;
}

/* ── The travelling particles ──────────────────────────────────────────
   offset-path follows the same geometry as the track, so the motion is
   exactly the flow being described. */
.s-chain__particle {
  fill: var(--a-amber-light);
  offset-path: path("M 104 130 L 1096 130");
  offset-rotate: 0deg;
  animation: s-chain-run 6s linear infinite;
}
.s-chain__particle--2 { animation-delay: -2s; }
.s-chain__particle--3 { animation-delay: -4s; }
@keyframes s-chain-run {
  0%        { offset-distance: 0%;   opacity: 0; }
  6%        { opacity: 1; }
  94%       { opacity: 1; }
  100%      { offset-distance: 100%; opacity: 0; }
}

/* ── Stage nodes ───────────────────────────────────────────────────────── */
.s-chain__halo {
  fill: none; stroke: rgba(127,188,228,.28); stroke-width: 1;
  transform-box: fill-box; transform-origin: center;
  animation: s-chain-halo 3.6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .28s);
}
@keyframes s-chain-halo {
  0%, 100% { transform: scale(1);    opacity: .5; }
  50%      { transform: scale(1.16); opacity: .12; }
}

.s-chain__disc  { fill: var(--c-navy); stroke: var(--c-azure-on-dark); stroke-width: 1.5; }
.s-chain__index {
  fill: var(--c-azure-on-dark); font-family: var(--f-mono); font-size: 13px; font-weight: 600;
}

.s-chain__label {
  fill: #fff; font-family: var(--f-sans); font-size: 15px;
  font-weight: var(--fw-semi); letter-spacing: -.02em;
}
.s-chain__sub {
  fill: var(--t-on-dark-muted); font-family: var(--f-sans); font-size: 12.5px;
}

/* The return path passes behind two of the sub-labels. Painting a stroke in
   the ground colour underneath the glyphs knocks the line out around the
   text, which is how technical diagrams handle a crossing without moving
   either element. */
.s-chain__sub,
.s-chain__label {
  paint-order: stroke fill;
  stroke: var(--c-ink);
  stroke-width: 5px;
  stroke-linejoin: round;
}

/* ── Arrival ───────────────────────────────────────────────────────────
   Stages light left to right, then the loop takes over and keeps running. */
.s-chain__figure.is-pending { opacity: 1; transform: none; }
.s-chain__figure.is-revealed .s-chain__stage {
  animation: s-chain-lite .5s var(--ease-out) backwards;
  animation-delay: calc(.15s + var(--i) * .13s);
}
@keyframes s-chain-lite { from { opacity: 0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
  .s-chain__particle,
  .s-chain__halo,
  .s-chain__feedback,
  .s-chain__figure.is-revealed .s-chain__stage { animation: none; }
  .s-chain__particle { opacity: 1; offset-distance: 50%; }
  .s-chain__feedback { stroke-dasharray: none; }
  .s-chain__halo { opacity: .4; }
}

}

/* ── components.css ─────────────────────────── */
/* ── Technology components ────────────────────────────────────────────────
   A ruled list, not a card grid. Each item is separated by a hairline that
   carries the pillar's hue at its start. */
@layer sections {

.s-components__list {
  display: grid; gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  grid-auto-rows: auto auto;
  /* the gap does the separating; padding on individual items cannot, because
     the column count changes with the viewport */
  column-gap: var(--sp-7);
  border-top: 1px solid var(--line);
}
/* Rows align on their own internal lines, so a two-line name in one column
   does not push its neighbour's body text out of step. */
.s-components__item {
  position: relative; padding: var(--sp-5) 0;
  border-bottom: 1px solid var(--line);
  display: grid; grid-template-rows: subgrid; grid-row: span 2;
  gap: var(--sp-3); align-content: start;
}
@supports not (grid-template-rows: subgrid) {
  .s-components__item { display: block; }
}
.s-components__item::before {
  content: ""; position: absolute; top: -1px; left: 0;
  width: 2.5rem; height: 2px; background: var(--s-comp-hue);
}
.s-components__name { margin: 0; font-size: var(--fs-h4); }
.s-components__item p { font-size: var(--fs-small); color: var(--t-body); line-height: 1.6; max-width: 44ch; }

.s-components__list--ai         { --s-comp-hue: var(--d-ai); }
.s-components__list--automation { --s-comp-hue: var(--d-automation); }
.s-components__list--robotics   { --s-comp-hue: var(--d-robotics); }
.s-components__list--networks   { --s-comp-hue: var(--d-networks); }

}

/* ── contact-form.css ─────────────────────────── */
/* ── Contact form ─────────────────────────────────────────────────────── */
@layer sections {

/* The intro is short and the form is tall. Centring leaves the intro
   floating in the middle of an empty column, so this split top-aligns. */
.s-contact .l-split { align-items: start; }

.s-contact__title { margin: var(--sp-5) 0 var(--sp-5); }
.s-contact__intro p { color: var(--t-body); }
.s-contact__direct { margin-top: var(--sp-5); font-size: var(--fs-small); }

.s-contact__form-wrap { width: 100%; max-width: 38rem; }
.s-contact__form { display: grid; gap: var(--sp-5); }
.s-contact__row {
  display: grid; gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
}
.s-contact__field { display: grid; gap: var(--sp-2); }
.s-contact__field label { font-size: var(--fs-small); font-weight: var(--fw-medium); }
.s-contact__req { color: var(--a-amber-deep); }

.s-contact__field :is(input, select, textarea) {
  width: 100%; padding: var(--sp-3) var(--sp-4);
  background: var(--g-paper);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: var(--fs-body); color: var(--t-strong);
  transition: border-color var(--dur-fast) var(--ease);
}
.s-contact__field :is(input, select, textarea):focus {
  border-color: var(--c-blue); outline-offset: 1px;
}
.s-contact__field textarea { resize: vertical; min-height: 8rem; }
.s-contact__hint { font-size: var(--fs-small); color: var(--t-muted); }

.s-contact__consent {
  display: grid; grid-template-columns: auto 1fr; gap: var(--sp-3);
  align-items: start;
}
.s-contact__consent label { font-size: var(--fs-small); color: var(--t-body); line-height: 1.5; }
.s-contact__consent input { margin-top: .25em; }

.s-contact__submit { justify-self: start; }

/* The honeypot must be reachable by a bot and invisible to a person, without
   using display:none, which some bots detect and skip. */
.s-contact__trap {
  position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden;
}

.s-contact__notice {
  padding: var(--sp-4) var(--sp-5); border-radius: var(--r-sm);
  margin-bottom: var(--sp-6); font-size: var(--fs-small);
}
.s-contact__notice--ok {
  background: color-mix(in srgb, var(--s-valid) 12%, transparent);
  color: var(--s-valid);
}
.s-contact__notice--bad {
  background: color-mix(in srgb, var(--s-blocked) 12%, transparent);
  color: var(--s-blocked);
}

}

/* ── converge.css ─────────────────────────── */
/* ── Signature visual: four domains, one intelligence layer ───────────────
   Continuous by design: the outer ring rotates, the core breathes, and one
   packet per domain runs inward on a loop. Convergence is ongoing, so the
   diagram never settles into a still frame.

   Performance: six animated elements total, all on transform/opacity or
   offset-distance. No filters, no shadows, nothing that forces repaint. */
@layer sections {

/* Capped so the diagram stays dense on a wide monitor instead of stretching
   into a thin ring adrift in empty space. */
.s-converge__figure {
  margin: var(--sp-6) auto 0; min-width: 40rem; max-width: 60rem;
}

.s-converge__field { opacity: .85; }

.s-converge__ring { fill: none; stroke: var(--c-azure); }
.s-converge__ring--mid   { stroke-width: 1.5; opacity: .2; stroke-dasharray: 3 9; }
.s-converge__ring--outer {
  stroke-width: 1; opacity: .16;
  transform-box: fill-box; transform-origin: center;
  animation: s-conv-rotate 90s linear infinite;
}
@keyframes s-conv-rotate { to { transform: rotate(360deg); } }

.s-converge__ticks line { stroke: var(--c-azure); stroke-width: 1; opacity: .18; }
.s-converge__ticks line.is-major { opacity: .38; stroke-width: 1.5; }

/* Spokes carry each domain's own hue, so the colour coding survives the
   diagram rather than being applied only to the labels. */
.s-converge__spoke { stroke-width: 2; opacity: .3; stroke-linecap: round; }
.s-converge__spoke--ai         { stroke: var(--d-ai); }
.s-converge__spoke--automation { stroke: var(--d-automation); }
.s-converge__spoke--robotics   { stroke: var(--d-robotics); }
.s-converge__spoke--networks   { stroke: var(--d-networks); }

.s-converge__packet {
  offset-rotate: 0deg;
  animation: s-conv-feed 3.4s var(--ease) infinite;
}
.s-converge__packet--ai         { fill: var(--d-ai);         animation-delay: 0s; }
.s-converge__packet--automation { fill: var(--d-automation); animation-delay: .85s; }
.s-converge__packet--robotics   { fill: var(--d-robotics);   animation-delay: 1.7s; }
.s-converge__packet--networks   { fill: var(--d-networks);   animation-delay: 2.55s; }
@keyframes s-conv-feed {
  0%       { offset-distance: 0%;   opacity: 0; }
  12%      { opacity: 1; }
  82%      { opacity: 1; }
  100%     { offset-distance: 100%; opacity: 0; }
}

/* The shared layer breathes — it is receiving, continuously */
.s-converge__pulse {
  fill: none; stroke: var(--c-azure); stroke-width: 1.5;
  transform-box: fill-box; transform-origin: center;
  animation: s-conv-breathe 4.2s var(--ease) infinite;
}
@keyframes s-conv-breathe {
  0%, 100% { transform: scale(1);    opacity: .38; }
  50%      { transform: scale(1.22); opacity: 0; }
}

.s-converge__core { fill: url(#s-conv-core); }
.s-converge__core-label,
.s-converge__core-sub { fill: #fff; font-family: var(--f-sans); letter-spacing: -.02em; }
.s-converge__core-label { font-size: 19px; font-weight: var(--fw-semi); }
.s-converge__core-sub   { font-size: 11.5px; opacity: .72; letter-spacing: .05em; text-transform: uppercase; }

.s-converge__node-halo { fill: var(--g-mist); stroke: var(--s-conv-hue); stroke-width: 1; opacity: .5; }
.s-converge__node-disc { fill: #fff; stroke: var(--s-conv-hue); stroke-width: 2.5; }

/* One hue per node, set once and read by the disc, halo, glyph and label —
   the same pattern the pillars use, so adding a domain means adding one line. */
.s-converge__node--ai         { --s-conv-hue: var(--d-ai); }
.s-converge__node--automation { --s-conv-hue: var(--d-automation); }
.s-converge__node--robotics   { --s-conv-hue: var(--d-robotics); }
.s-converge__node--networks   { --s-conv-hue: var(--d-networks); }

.s-converge__glyph {
  fill: none; stroke: var(--s-conv-hue);
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.s-converge__glyph .is-dot { fill: var(--s-conv-hue); stroke: none; }

.s-converge__node-label {
  font-family: var(--f-sans); font-size: 15.5px; font-weight: var(--fw-semi);
  letter-spacing: -.02em; fill: var(--s-conv-hue);
}
.s-converge__node-sub { font-family: var(--f-sans); font-size: 11.5px; fill: var(--t-muted); }

/* Arrival: assembles in reading order, then the loops take over */
.s-converge__figure.is-pending { opacity: 1; transform: none; }
.s-converge__figure.is-revealed .s-converge__node {
  animation: s-conv-pop .55s var(--ease-out) backwards;
}
.s-converge__figure.is-revealed .s-converge__node--ai         { animation-delay: .10s; }
.s-converge__figure.is-revealed .s-converge__node--automation { animation-delay: .20s; }
.s-converge__figure.is-revealed .s-converge__node--robotics   { animation-delay: .30s; }
.s-converge__figure.is-revealed .s-converge__node--networks   { animation-delay: .40s; }
@keyframes s-conv-pop { from { opacity: 0; transform: translateY(10px); } }

@media (prefers-reduced-motion: reduce) {
  .s-converge__ring--outer,
  .s-converge__pulse,
  .s-converge__packet,
  .s-converge__figure.is-revealed .s-converge__node { animation: none; }
  .s-converge__packet { opacity: 1; offset-distance: 55%; }
  .s-converge__pulse  { opacity: .3; }
}

}

/* ── cta.css ─────────────────────────── */
/* ── Closing call to action ─────────────────────────────────────────────── */
@layer sections {

.s-cta__inner { text-align: center; }
.s-cta__title { max-width: 18ch; margin: var(--sp-5) auto var(--sp-5); }
.s-cta__lead  { max-width: 52ch; margin-inline: auto; font-size: var(--fs-lead); line-height: 1.5; }
.s-cta__actions { margin-top: var(--sp-5); }

}

/* ── diagram-due-diligence.css ─────────────────────────── */
/* ── Due diligence illustration ──────────────────────────────────────────
   A live operations picture. Layers, from the back: grid, dot-matrix world,
   the links and their traffic, the endpoints, the hub, the lens over Europe,
   and the analysis panels around the edge.

   Performance: the 3,596 map dots are one path. Roughly twenty elements
   animate, all on transform, opacity or offset-distance. Everything stops
   under prefers-reduced-motion, and the picture stays fully readable. */
@layer sections {

.s-dd__field { fill: var(--c-ink); }

/* ── the world ────────────────────────────────────────────────────────── */
/* Bold enough to read as a map, not a texture. */
.s-dd__map {
  fill: none; stroke: var(--c-azure-on-dark);
  stroke-width: 3.4; stroke-linecap: round; opacity: .74;
}

/* The countries this service connects, lit against the rest: finer spacing
   and a warmer, brighter ink, so they read as solid landmasses. */
.s-dd__map--focus {
  stroke: var(--a-amber-light); stroke-width: 3.4; opacity: .95;
  animation: s-dd-focus 6s var(--ease) infinite;
}
@keyframes s-dd-focus {
  0%, 100% { opacity: .82; }
  50%      { opacity: 1; }
}

.s-dd__grat line { stroke: var(--c-azure-on-dark); stroke-width: 1; opacity: .12; }


/* ── links ────────────────────────────────────────────────────────────── */
.s-dd__arc {
  fill: none; stroke: var(--c-azure-on-dark); stroke-width: 1.8;
  opacity: .8; stroke-dasharray: 4 5;
  animation: s-dd-flowline 4s linear infinite;
  animation-delay: calc(var(--i) * -0.4s);
}
/* the transatlantic hop is the long one; amber marks it as the outlier */
.s-dd__arc--far { stroke: var(--a-amber); opacity: .95; stroke-width: 2.4; }
@keyframes s-dd-flowline { to { stroke-dashoffset: -16; } }

.s-dd__pkt { offset-rotate: 0deg; }
.s-dd__pkt--in {
  fill: var(--a-amber);
  animation: s-dd-in 4.4s var(--ease) infinite;
  animation-delay: calc(var(--i) * .32s);
}
.s-dd__pkt--out {
  fill: var(--c-azure-on-dark);
  animation: s-dd-out 4.4s var(--ease) infinite;
  animation-delay: calc(var(--i) * .32s + 2.2s);
}
@keyframes s-dd-in {
  0%   { offset-distance: 0%;   opacity: 0; }
  8%   { opacity: 1; }
  42%  { opacity: 1; }
  50%  { offset-distance: 100%; opacity: 0; }
  100% { offset-distance: 100%; opacity: 0; }
}
@keyframes s-dd-out {
  0%   { offset-distance: 100%; opacity: 0; }
  8%   { opacity: 1; }
  42%  { opacity: 1; }
  50%  { offset-distance: 0%;   opacity: 0; }
  100% { offset-distance: 0%;   opacity: 0; }
}

/* ── endpoints ────────────────────────────────────────────────────────── */
.s-dd__dot  { fill: var(--dg-text-on-dark); }
.s-dd__ping {
  fill: none; stroke: var(--c-azure-on-dark); stroke-width: 1.6;
  transform-box: fill-box; transform-origin: center;
  animation: s-dd-ping 3.6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .28s);
}
@keyframes s-dd-ping {
  0%, 100% { transform: scale(.7); opacity: .9; }
  60%      { transform: scale(2.4); opacity: 0; }
}

/* ── the hub ──────────────────────────────────────────────────────────── */
.s-dd__hub { fill: var(--a-amber); }
.s-dd__hub-ring {
  fill: none; stroke: var(--a-amber); stroke-width: 1.4;
  transform-box: fill-box; transform-origin: center;
  animation: s-dd-hubring 3s var(--ease) infinite;
  animation-delay: calc(var(--r) * 1s);
}
@keyframes s-dd-hubring {
  0%   { transform: scale(.5); opacity: .9; }
  100% { transform: scale(4.2); opacity: 0; }
}
.s-dd__crosshair {
  stroke: var(--a-amber); stroke-width: 1.4; opacity: .75; stroke-linecap: round;
  transform-box: fill-box; transform-origin: center;
  animation: s-dd-spin 24s linear infinite;
}
@keyframes s-dd-spin { to { transform: rotate(360deg); } }

/* ── the lens ─────────────────────────────────────────────────────────── */
/* a wash, not a fill: the cluster underneath has to stay visible */
.s-dd__lens-wash { fill: var(--c-azure-on-dark); opacity: .07; }
.s-dd__lens-rim  { fill: none; stroke: url(#dd-rim); stroke-width: 5; }
.s-dd__lens-ticks line { stroke: var(--c-azure-on-dark); stroke-width: 1.4; opacity: .45; }
.s-dd__lens-scan {
  stroke: var(--a-amber-light); stroke-width: 1.6; opacity: .7;
  animation: s-dd-lensscan 5s var(--ease) infinite;
}
@keyframes s-dd-lensscan {
  0%   { transform: translateY(0);    opacity: 0; }
  10%  { opacity: .7; }
  90%  { transform: translateY(236px); opacity: .7; }
  100% { transform: translateY(236px); opacity: 0; }
}

/* ── analysis panels ──────────────────────────────────────────────────── */
.s-dd__panel > rect:first-child {
  fill: var(--dg-panel-on-dark); stroke: var(--c-azure-on-dark); stroke-width: 1; stroke-opacity: .22;
}
.s-dd__bar {
  fill: var(--c-azure-on-dark); opacity: .55;
  transform-box: fill-box; transform-origin: center bottom;
  animation: s-dd-bar 5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .14s);
}
@keyframes s-dd-bar { 0%, 100% { transform: scaleY(1); } 50% { transform: scaleY(.55); } }
.s-dd__spark {
  fill: none; stroke: var(--a-amber); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 260; stroke-dashoffset: 260;
  animation: s-dd-spark 5s var(--ease) infinite;
}
@keyframes s-dd-spark { 0% { stroke-dashoffset: 260; } 55%, 100% { stroke-dashoffset: 0; } }

.s-dd__donut { fill: none; stroke: var(--c-azure-on-dark); stroke-width: 9; opacity: .2; }
.s-dd__donut-arc {
  fill: none; stroke: var(--a-amber-light); stroke-width: 9; stroke-linecap: round;
  stroke-dasharray: 214; stroke-dashoffset: 150;
  transform: rotate(-90deg); transform-origin: 104px 258px;
  animation: s-dd-donut 6s var(--ease) infinite;
}
@keyframes s-dd-donut {
  0%, 100% { stroke-dashoffset: 160; }
  50%      { stroke-dashoffset: 96; }
}
.s-dd__row {
  fill: var(--c-azure-on-dark); opacity: .28;
  transform-box: fill-box; transform-origin: left center;
  animation: s-dd-row 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .3s);
}
@keyframes s-dd-row { 0%, 100% { transform: scaleX(1); } 50% { transform: scaleX(.6); } }

.s-dd__radar-ring { fill: none; stroke: var(--c-azure-on-dark); stroke-width: 1; opacity: .3; }
.s-dd__radar-sweep {
  transform-box: fill-box; transform-origin: 1052px 446px;
  animation: s-dd-spin 4.5s linear infinite;
}
.s-dd__radar-beam { fill: var(--c-azure-on-dark); opacity: .18; }
.s-dd__blip {
  fill: var(--a-amber);
  animation: s-dd-blip 4.5s var(--ease) infinite;
  animation-delay: calc(var(--i) * 1.2s);
}
@keyframes s-dd-blip { 0%, 70%, 100% { opacity: .15; } 6%, 20% { opacity: 1; } }

.s-dd__cell {
  fill: var(--c-azure-on-dark); opacity: .16;
  animation: s-dd-cell 7s var(--ease) infinite;
  animation-delay: calc(var(--i) * .34s);
}
@keyframes s-dd-cell { 0%, 82%, 100% { opacity: .16; } 8%, 20% { opacity: .8; } }

.s-dd__bracket path {
  fill: none; stroke: var(--a-amber); stroke-width: 2; opacity: .55; stroke-linecap: round;
}
.s-dd__sweep {
  stroke: var(--c-azure-on-dark); stroke-width: 2; opacity: .16;
  animation: s-dd-sweep 9s linear infinite;
}
@keyframes s-dd-sweep {
  0%   { transform: translateX(0);      opacity: 0; }
  8%   { opacity: .16; }
  92%  { opacity: .16; }
  100% { transform: translateX(1200px); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .s-dd__arc, .s-dd__pkt, .s-dd__ping, .s-dd__hub-ring, .s-dd__crosshair,
  .s-dd__lens-scan, .s-dd__bar, .s-dd__spark, .s-dd__donut-arc, .s-dd__row,
  .s-dd__radar-sweep, .s-dd__blip, .s-dd__cell, .s-dd__sweep { animation: none; }
  .s-dd__pkt   { opacity: 1; offset-distance: 50%; }
  .s-dd__spark { stroke-dashoffset: 0; }
  .s-dd__blip, .s-dd__cell { opacity: .7; }
  .s-dd__sweep, .s-dd__lens-scan { opacity: 0; }
}

}

/* ── diagram-embodied.css ─────────────────────────── */
/* ── The embodied loop ───────────────────────────────────────────────────
   Three things run at once and deliberately not in step: sensors feeding the
   loop, the loop itself turning, and the learning path returning. That is the
   claim the diagram makes — the agent is not stepping through a script under
   a central clock.

   Everything stops under prefers-reduced-motion and stays fully readable. */
@layer sections {

/* ── the world ────────────────────────────────────────────────────────── */
.s-emb__world-frame {
  fill: none; stroke: var(--dg-line); stroke-width: 1.5; stroke-dasharray: 6 6;
}
.s-emb__world-label {
  fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase;
}
.s-emb__object {
  fill: var(--d-robotics); opacity: .3;
  animation: s-emb-object 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .5s);
}
@keyframes s-emb-object { 0%, 70%, 100% { opacity: .28; } 12%, 26% { opacity: .85; } }

/* the sensing cone sweeps the world; the action arrow reaches back into it */
.s-emb__sense-beam {
  fill: var(--d-robotics); opacity: .07;
  transform-box: fill-box; transform-origin: 100% 50%;
  animation: s-emb-beam 6s var(--ease) infinite;
}
@keyframes s-emb-beam {
  0%, 100% { transform: rotate(-7deg); opacity: .05; }
  50%      { transform: rotate(7deg);  opacity: .12; }
}
.s-emb__act-arrow {
  fill: none; stroke: var(--a-amber); stroke-width: 1.8; stroke-dasharray: 5 5;
  animation: s-emb-act 6s linear infinite;
}
@keyframes s-emb-act { to { stroke-dashoffset: -20; } }
.s-emb__tip    { fill: var(--a-amber); }
.s-emb__tip-in { fill: var(--d-automation); }

/* ── sensors ──────────────────────────────────────────────────────────── */
.s-emb__sensor-disc {
  fill: var(--dg-surface); stroke: var(--d-robotics); stroke-width: 2;
  animation: s-emb-sensor 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .3s);
}
@keyframes s-emb-sensor {
  0%, 60%, 100% { stroke-width: 2; }
  8%, 20%       { stroke-width: 3.4; }
}
.s-emb__sensor-glyph {
  fill: none; stroke: var(--d-robotics); stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.s-emb__sensor-glyph rect:first-child { fill: none; }

.s-emb__feed { fill: none; stroke: var(--d-robotics); stroke-width: 1.4; opacity: .25; stroke-dasharray: 3 5; }
.s-emb__feed-pkt {
  fill: var(--d-robotics); offset-rotate: 0deg;
  animation: s-emb-feed 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .3s);
}
@keyframes s-emb-feed {
  0%   { offset-distance: 0%;   opacity: 0; }
  6%   { opacity: 1; }
  24%  { opacity: 1; }
  30%  { offset-distance: 100%; opacity: 0; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* ── the loop ─────────────────────────────────────────────────────────── */
.s-emb__ring { fill: none; stroke: var(--d-robotics); stroke-width: 1.5; opacity: .28; stroke-dasharray: 4 8; }

.s-emb__halo {
  fill: none; stroke: var(--d-robotics); stroke-width: 1.4;
  transform-box: fill-box; transform-origin: center;
  animation: s-emb-halo 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * 1s);
}
@keyframes s-emb-halo {
  0%, 84%, 100% { transform: scale(1); opacity: 0; }
  6%            { transform: scale(1); opacity: .9; }
  22%           { transform: scale(1.7); opacity: 0; }
}
.s-emb__node {
  fill: var(--dg-surface); stroke: var(--d-robotics); stroke-width: 2.5;
  animation: s-emb-node 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * 1s);
}
@keyframes s-emb-node {
  0%, 84%, 100% { fill: var(--dg-surface); }
  6%, 18%       { fill: var(--d-robotics-tint); }
}
.s-emb__index { fill: var(--d-robotics); font-family: var(--f-mono); font-size: 12px; font-weight: 600; }
.s-emb__label { fill: var(--dg-text); font-family: var(--f-sans); font-size: 14px; font-weight: var(--fw-semi); letter-spacing: -.02em; }
.s-emb__sub   { fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11px; }

.s-emb__token {
  fill: var(--d-robotics); offset-rotate: 0deg;
  animation: s-emb-run 6s linear infinite;
}
@keyframes s-emb-run { to { offset-distance: 100%; } }

/* ── memory ───────────────────────────────────────────────────────────── */
.s-emb__memory rect:first-child {
  fill: var(--dg-surface-soft); stroke: var(--d-robotics); stroke-width: 1.5; stroke-opacity: .4;
}
.s-emb__mem-row {
  fill: var(--d-robotics); opacity: .3;
  transform-box: fill-box; transform-origin: left center;
  animation: s-emb-mem 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .4s);
}
@keyframes s-emb-mem {
  0%, 100% { transform: scaleX(1); opacity: .3; }
  40%      { transform: scaleX(.72); opacity: .65; }
}
.s-emb__mem-label {
  fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11px;
  letter-spacing: .06em; text-transform: uppercase;
}
.s-emb__mem-link { stroke: var(--d-robotics); stroke-width: 1.4; opacity: .3; stroke-dasharray: 3 4; }

/* ── safety gate ──────────────────────────────────────────────────────── */
.s-emb__gate rect {
  fill: var(--dg-surface); stroke: var(--a-amber); stroke-width: 2;
  animation: s-emb-gate 6s var(--ease) infinite;
}
@keyframes s-emb-gate {
  0%, 72%, 100% { stroke-width: 2; }
  78%, 88%      { stroke-width: 3.4; }
}
.s-emb__gate-check {
  fill: none; stroke: var(--a-amber); stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 34; stroke-dashoffset: 34;
  animation: s-emb-check 6s var(--ease) infinite;
}
@keyframes s-emb-check {
  0%, 74%   { stroke-dashoffset: 34; }
  84%, 100% { stroke-dashoffset: 0; }
}
.s-emb__gate-label {
  fill: var(--a-amber-deep); font-family: var(--f-sans); font-size: 10.5px;
  letter-spacing: .05em; text-transform: uppercase;
}
.l-section--ink .s-emb__gate-label { fill: var(--a-amber-light); }

/* ── reasoning methods ────────────────────────────────────────────────── */
.s-emb__branch { fill: none; stroke: var(--d-robotics); stroke-width: 1.3; opacity: .3; }
.s-emb__branch-dot {
  fill: var(--d-robotics);
  animation: s-emb-branch 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .25s + 2.6s);
}
@keyframes s-emb-branch { 0%, 60%, 100% { opacity: .3; } 8%, 24% { opacity: 1; } }
.s-emb__branch-label { fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11px; }

/* ── learning returns ─────────────────────────────────────────────────── */
.s-emb__learn {
  fill: none; stroke: var(--d-automation); stroke-width: 1.6;
  opacity: .45; stroke-dasharray: 5 6;
  animation: s-emb-learnline 4s linear infinite;
}
@keyframes s-emb-learnline { to { stroke-dashoffset: -22; } }
.s-emb__learn-label {
  fill: var(--d-automation); font-family: var(--f-sans); font-size: 11px;
  letter-spacing: .06em; text-transform: uppercase;
}
.s-emb__learn-pkt {
  fill: var(--d-automation); offset-rotate: 0deg;
  animation: s-emb-learnpkt 6s var(--ease) infinite;
}
@keyframes s-emb-learnpkt {
  0%, 56% { offset-distance: 0%; opacity: 0; }
  62%     { opacity: 1; }
  92%     { offset-distance: 100%; opacity: 1; }
  100%    { offset-distance: 100%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .s-emb__object, .s-emb__sense-beam, .s-emb__act-arrow, .s-emb__sensor-disc,
  .s-emb__feed-pkt, .s-emb__halo, .s-emb__node, .s-emb__token, .s-emb__mem-row,
  .s-emb__gate rect, .s-emb__gate-check, .s-emb__branch-dot, .s-emb__learn,
  .s-emb__learn-pkt { animation: none; }
  .s-emb__feed-pkt, .s-emb__learn-pkt { opacity: 1; offset-distance: 50%; }
  .s-emb__token { offset-distance: 12%; }
  .s-emb__halo { opacity: .3; }
  .s-emb__gate-check { stroke-dashoffset: 0; }
  .s-emb__object { opacity: .5; }
}

}

/* ── diagram-federated.css ─────────────────────────── */
/* ── Federated learning diagram ──────────────────────────────────────────
   The claim the drawing must never undermine: raw data does not cross a site
   boundary. Site boxes are closed, the dataset sits inside them, and the only
   thing animating along the wire is a parameter packet.

   Motion is the explanation here, so it loops: updates rise, the aggregator
   averages, the improved model returns, and the cycle repeats. */
@layer sections {

.s-fed__round rect { fill: var(--dg-surface-soft); stroke: var(--dg-line); stroke-width: 1; }
.s-fed__round text {
  fill: var(--dg-text-muted); font-family: var(--f-mono); font-size: 10.5px;
}

/* ── aggregator ───────────────────────────────────────────────────────── */
.s-fed__agg { fill: var(--c-blue); }
.s-fed__agg-label { fill: #fff; font-family: var(--f-sans); font-size: 17px; font-weight: var(--fw-semi); }
.s-fed__agg-sub   { fill: #fff; opacity: .72; font-family: var(--f-sans); font-size: 11.5px; }

/* the three incoming weights, rising and settling as they are averaged */
.s-fed__avg-bar {
  fill: #fff; opacity: .5;
  transform-box: fill-box; transform-origin: center bottom;
  animation: s-fed-avg 4.8s var(--ease) infinite;
  animation-delay: calc(var(--i) * .2s);
}
@keyframes s-fed-avg {
  0%, 40%   { transform: scaleY(.35); opacity: .35; }
  55%, 70%  { transform: scaleY(1);   opacity: .85; }
  100%      { transform: scaleY(.35); opacity: .35; }
}
.s-fed__avg-sum { stroke: #fff; stroke-width: 1.5; opacity: .5; stroke-linecap: round; }

/* ── wires ────────────────────────────────────────────────────────────── */
.s-fed__wire { fill: none; stroke-width: 1.5; }
.s-fed__wire--up   { stroke: var(--c-azure); opacity: .3; stroke-dasharray: 4 6; }
.s-fed__wire--down { stroke: var(--d-automation); opacity: .18; }

.s-fed__packet { offset-rotate: 0deg; animation: s-fed-run 4.8s var(--ease) infinite; animation-delay: var(--d, 0s); }
.s-fed__packet--up   { fill: var(--c-azure); }
.s-fed__packet--down { fill: var(--d-automation); }
@keyframes s-fed-run {
  0%   { offset-distance: 0%;   opacity: 0; }
  6%   { opacity: 1; }
  38%  { opacity: 1; }
  44%  { offset-distance: 100%; opacity: 0; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* ── sites ────────────────────────────────────────────────────────────── */
.s-fed__site { fill: var(--dg-surface); stroke: var(--dg-line); stroke-width: 1.5; }
.s-fed__site-label { fill: var(--dg-text); font-family: var(--f-sans); font-size: 13.5px; font-weight: var(--fw-semi); }

.s-fed__data { fill: var(--d-ai-tint); }
.s-fed__row  { fill: var(--c-blue); opacity: .45; }
.s-fed__data-label { fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11px; }

/* the local model, stepping through a training round */
.s-fed__model {
  fill: none; stroke: var(--c-blue); stroke-width: 2;
  transform-box: fill-box; transform-origin: center;
  animation: s-fed-train 4.8s var(--ease) infinite; animation-delay: var(--d, 0s);
}
@keyframes s-fed-train {
  0%, 100% { transform: scale(1);    opacity: .55; }
  18%      { transform: scale(1.12); opacity: 1; }
  36%      { transform: scale(1);    opacity: .55; }
}
.s-fed__model-mark { fill: var(--c-blue); opacity: .8; }
.s-fed__local { stroke: var(--c-blue); stroke-width: 1.5; opacity: .35; stroke-dasharray: 3 4; }

.s-fed__stay {
  fill: var(--a-amber-deep); font-family: var(--f-sans); font-size: 10px;
  letter-spacing: .06em; text-transform: uppercase;
}
.l-section--ink .s-fed__stay { fill: var(--a-amber-light); }

/* The wires pass behind these labels; a knockout in the ground colour keeps
   both readable without moving either. */
.s-fed__flow {
  font-family: var(--f-sans); font-size: 12px; font-weight: var(--fw-medium);
  paint-order: stroke fill; stroke: var(--g-mist); stroke-width: 6px; stroke-linejoin: round;
}
.l-section--ink .s-fed__flow { stroke: var(--c-ink); }
.s-fed__flow--up   { fill: var(--c-azure-text); }
.s-fed__flow--down { fill: var(--d-automation); }
.l-section--ink .s-fed__flow--up { fill: var(--c-azure-on-dark); }

@media (prefers-reduced-motion: reduce) {
  .s-fed__packet, .s-fed__model, .s-fed__avg-bar { animation: none; }
  .s-fed__packet { opacity: 1; offset-distance: 50%; }
  .s-fed__model  { opacity: 1; }
  .s-fed__avg-bar { opacity: .6; }
}

}

/* ── diagram-isac.css ─────────────────────────── */
/* ── Integrated sensing and communications ───────────────────────────────
   One emission, two jobs. The comm path and the sensing path run on the same
   cadence and start together, because they are the same transmission — that
   simultaneity is the whole claim. The return arrives late, as a reflection
   does, and the readout lights when it lands. */
@layer sections {

.s-isac__mast    { fill: none; stroke: var(--d-networks); stroke-width: 2.6; stroke-linecap: round; }
.s-isac__tip-dot { fill: var(--d-networks); }
.s-isac__tip     { fill: var(--d-networks); }

.s-isac__label { fill: var(--dg-text); font-family: var(--f-sans); font-size: 14px; font-weight: var(--fw-semi); }
.s-isac__sub   { fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11.5px; }
.s-isac__job {
  fill: var(--d-networks); font-family: var(--f-sans); font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase;
  paint-order: stroke fill; stroke: var(--dg-surface); stroke-width: 5px; stroke-linejoin: round;
}
.s-isac__job--sense { fill: var(--a-amber-deep); }
.l-section--ink .s-isac__job--sense { fill: var(--a-amber-light); }

/* the emission itself */
.s-isac__emit {
  fill: none; stroke: var(--d-networks); stroke-width: 2; stroke-linecap: round;
  animation: s-isac-emit 3.2s var(--ease) infinite;
  animation-delay: calc(var(--i) * .32s);
}
@keyframes s-isac-emit { 0% { opacity: 0; } 25% { opacity: .75; } 100% { opacity: 0; } }

/* job one: data */
.s-isac__comm { fill: none; stroke: var(--d-networks); stroke-width: 1.8; opacity: .5; stroke-dasharray: 5 6; }
.s-isac__bit {
  fill: var(--d-networks); offset-rotate: 0deg;
  animation: s-isac-travel 3.2s var(--ease) infinite;
}
@keyframes s-isac-travel {
  0%   { offset-distance: 0%;   opacity: 0; }
  8%   { opacity: 1; }
  52%  { opacity: 1; }
  60%  { offset-distance: 100%; opacity: 0; }
  100% { offset-distance: 100%; opacity: 0; }
}
.s-isac__rx { fill: var(--dg-surface); stroke: var(--d-networks); stroke-width: 2; }

/* job two: the same emission, reflecting */
.s-isac__out { fill: none; stroke: var(--a-amber); stroke-width: 1.8; opacity: .5; stroke-dasharray: 5 6; }
.s-isac__probe {
  fill: var(--a-amber); offset-rotate: 0deg;
  animation: s-isac-travel 3.2s var(--ease) infinite;
}
.s-isac__back { fill: none; stroke: var(--a-amber-light); stroke-width: 1.6; opacity: .45; }
.s-isac__return {
  fill: var(--a-amber-light); offset-rotate: 0deg;
  animation: s-isac-return 3.2s var(--ease) infinite;
}
/* the return starts only once the probe has arrived */
@keyframes s-isac-return {
  0%, 46% { offset-distance: 0%; opacity: 0; }
  54%     { opacity: 1; }
  94%     { offset-distance: 100%; opacity: 1; }
  100%    { offset-distance: 100%; opacity: 0; }
}

/* the object that reflects it, moving as objects do */
.s-isac__target { animation: s-isac-move 6.4s ease-in-out infinite alternate; }
@keyframes s-isac-move { from { transform: translateX(0); } to { transform: translateX(-34px); } }
.s-isac__vehicle { fill: var(--dg-surface); stroke: var(--a-amber); stroke-width: 2.2; }
.s-isac__wheel   { fill: var(--dg-surface); stroke: var(--a-amber); stroke-width: 2; }
.s-isac__echo {
  fill: none; stroke: var(--a-amber); stroke-width: 1.5;
  transform-box: fill-box; transform-origin: center;
  animation: s-isac-echo 3.2s var(--ease) infinite;
  animation-delay: .45s;
}
@keyframes s-isac-echo {
  0%, 100% { transform: scale(.6); opacity: 0; }
  20%      { transform: scale(.6); opacity: .9; }
  60%      { transform: scale(1.5); opacity: 0; }
}

/* what the return yields */
.s-isac__yield { stroke: var(--a-amber); stroke-width: 1.4; opacity: .3; stroke-dasharray: 3 4; }
.s-isac__readout rect { fill: var(--dg-surface-soft); stroke: var(--a-amber); stroke-width: 1.5; stroke-opacity: .5; }
.s-isac__readout-label {
  fill: var(--dg-text-muted); font-family: var(--f-mono); font-size: 11px;
}
.s-isac__dot {
  fill: var(--a-amber);
  animation: s-isac-lock 3.2s var(--ease) infinite;
  animation-delay: calc(2s + var(--i) * .18s);
}
@keyframes s-isac-lock { 0%, 70%, 100% { opacity: .25; } 8%, 28% { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .s-isac__emit, .s-isac__bit, .s-isac__probe, .s-isac__return, .s-isac__target,
  .s-isac__echo, .s-isac__dot { animation: none; }
  .s-isac__bit, .s-isac__probe { opacity: 1; offset-distance: 55%; }
  .s-isac__return { opacity: 1; offset-distance: 45%; }
  .s-isac__emit { opacity: .5; }
  .s-isac__echo { opacity: .35; transform: scale(1); }
  .s-isac__dot  { opacity: .8; }
}

}

/* ── diagram-multi-agent.css ─────────────────────────── */
/* ── Multi-agent orchestration diagram ───────────────────────────────────
   Two different motions carry the meaning: assignment travels downward from
   the orchestrator, and negotiation travels sideways between agents. Each
   agent's own loop runs continuously and independently, which is the point
   being made — they are not stepping in unison under a central clock. */
@layer sections {

.s-ma__orch { fill: var(--c-ink); }
.s-ma__orch-label { fill: #fff; font-family: var(--f-sans); font-size: 17px; font-weight: var(--fw-semi); }
.s-ma__orch-sub   { fill: #fff; opacity: .66; font-family: var(--f-sans); font-size: 11.5px; }

.s-ma__assign { fill: none; stroke: var(--c-azure); stroke-width: 1.5; opacity: .28; stroke-dasharray: 4 5; }
.s-ma__packet {
  fill: var(--c-azure); offset-rotate: 0deg;
  animation: s-ma-run 4.2s var(--ease) infinite; animation-delay: var(--d, 0s);
}
@keyframes s-ma-run {
  0%   { offset-distance: 0%;   opacity: 0; }
  8%   { opacity: 1; }
  46%  { opacity: 1; }
  54%  { offset-distance: 100%; opacity: 0; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* Wires pass behind these; knocking them out keeps both readable. */
.s-ma__flow, .s-ma__note {
  fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11.5px;
}
.s-ma__flow, .s-ma__step-label {
  paint-order: stroke fill; stroke: var(--dg-surface);
  stroke-width: 5px; stroke-linejoin: round;
}
.s-ma__flow { letter-spacing: .06em; text-transform: uppercase; font-size: 10.5px; }

/* ── agent ────────────────────────────────────────────────────────────── */
.s-ma__ring { fill: none; stroke: var(--s-ma-hue); stroke-width: 1.5; opacity: .3; stroke-dasharray: 3 7; }
.s-ma__core { fill: var(--dg-surface); stroke: var(--s-ma-hue); stroke-width: 2.5; }
.s-ma__name { fill: var(--dg-text); font-family: var(--f-sans); font-size: 13px; font-weight: var(--fw-semi); }
.s-ma__kind { fill: var(--s-ma-hue); font-family: var(--f-sans); font-size: 10.5px; }
.s-ma__domain { fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11.5px; }

/* each loop step lights in turn, offset per agent so they run independently */
.s-ma__step {
  fill: var(--dg-surface); stroke: var(--s-ma-hue); stroke-width: 2;
  animation: s-ma-step 5s var(--ease) infinite;
  animation-delay: calc(var(--d, 0s) + var(--j) * 1s);
}
@keyframes s-ma-step {
  0%, 88%, 100% { fill: var(--dg-surface); }
  6%, 14%       { fill: var(--s-ma-hue); }
}
.s-ma__step-label { fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 10.5px; }

.s-ma__token {
  fill: var(--s-ma-hue); offset-rotate: 0deg;
  animation: s-ma-loop 5s linear infinite; animation-delay: var(--d, 0s);
}
@keyframes s-ma-loop { to { offset-distance: 100%; } }

.s-ma__agent--ai         { --s-ma-hue: var(--d-ai); }
.s-ma__agent--automation { --s-ma-hue: var(--d-automation); }
.s-ma__agent--robotics   { --s-ma-hue: var(--d-robotics); }
.s-ma__agent--networks   { --s-ma-hue: var(--d-networks); }

/* ── peer negotiation ─────────────────────────────────────────────────── */
.s-ma__peer { fill: none; stroke: var(--d-automation); stroke-width: 1.5; stroke-dasharray: 5 6; opacity: .5; }
.s-ma__peer-token {
  fill: var(--d-automation); offset-rotate: 0deg;
  animation: s-ma-peer 3.4s var(--ease) infinite; animation-delay: var(--d, 0s);
}
/* back and forth: a negotiation is not a one-way send */
@keyframes s-ma-peer {
  0%   { offset-distance: 0%;   opacity: 0; }
  10%  { opacity: 1; }
  45%  { offset-distance: 100%; opacity: 1; }
  55%  { offset-distance: 100%; opacity: 1; }
  90%  { offset-distance: 0%;   opacity: 1; }
  100% { offset-distance: 0%;   opacity: 0; }
}
.s-ma__peer-label {
  fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 10px;
  letter-spacing: .06em; text-transform: uppercase;
  paint-order: stroke fill; stroke: var(--dg-surface); stroke-width: 5px; stroke-linejoin: round;
}

@media (prefers-reduced-motion: reduce) {
  .s-ma__packet, .s-ma__token, .s-ma__peer-token, .s-ma__step { animation: none; }
  .s-ma__packet, .s-ma__peer-token { opacity: 1; offset-distance: 50%; }
  .s-ma__token { offset-distance: 12%; }
}

}

/* ── diagram-network-topology.css ─────────────────────────── */
/* ── Terrestrial and non-terrestrial convergence ─────────────────────────
   Several things move at once, each on its own cadence: the satellite along
   its orbit with its beam, packets down the direct-to-device link, waves off
   the tower, the sensing return, and three slices carrying traffic to the
   core at different rates. That independence is the point — this is one
   network made of parts that do not share a clock. */
@layer sections {

/* ── orchestration ────────────────────────────────────────────────────── */
.s-net__orch { fill: url(#net-orch); }
.s-net__orch-label { fill: #fff; font-family: var(--f-sans); font-size: 16px; font-weight: var(--fw-semi); }
.s-net__orch-sub   { fill: #fff; opacity: .66; font-family: var(--f-sans); font-size: 11.5px; }
.s-net__ctrl { fill: none; stroke: var(--d-networks); stroke-width: 1.3; opacity: .28; stroke-dasharray: 3 4; }
.s-net__ctrl-pkt {
  fill: var(--d-networks); offset-rotate: 0deg;
  animation: s-net-ctrl 3.4s var(--ease) infinite;
  animation-delay: calc(var(--i) * .5s);
}
@keyframes s-net-ctrl {
  0%   { offset-distance: 0%;   opacity: 0; }
  12%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* ── orbit ────────────────────────────────────────────────────────────── */
.s-net__orbit { fill: none; stroke: var(--d-networks); stroke-width: 1.2; opacity: .25; stroke-dasharray: 5 7; }
.s-net__sat {
  offset-path: path("M120 214 Q420 118 720 214");
  offset-rotate: 0deg;
  animation: s-net-orbit 18s ease-in-out infinite alternate;
}
@keyframes s-net-orbit { from { offset-distance: 22%; } to { offset-distance: 62%; } }
.s-net__sat-body { fill: var(--dg-surface); stroke: var(--d-networks); stroke-width: 2; }
.s-net__sat-wing { stroke: var(--d-networks); stroke-width: 2; stroke-linecap: round; }

/* the beam it paints on the ground, tracking with it */
.s-net__beam {
  fill: var(--d-networks); opacity: .07;
  transform-box: fill-box; transform-origin: 50% 0;
  animation: s-net-beam 18s ease-in-out infinite alternate;
}
@keyframes s-net-beam { from { transform: skewX(9deg); } to { transform: skewX(-9deg); } }

.s-net__d2d { fill: none; stroke: var(--a-amber); stroke-width: 1.6; opacity: .5; stroke-dasharray: 5 6; }
.s-net__d2d-pkt {
  fill: var(--a-amber); offset-rotate: 0deg;
  animation: s-net-run 3s var(--ease) infinite;
}
@keyframes s-net-run {
  0%   { offset-distance: 0%;   opacity: 0; }
  12%  { opacity: 1; }
  82%  { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* ── terrestrial ──────────────────────────────────────────────────────── */
.s-net__tower     { fill: none; stroke: var(--d-networks); stroke-width: 2.4; stroke-linecap: round; }
.s-net__tower-tip { fill: var(--d-networks); }
.s-net__wave {
  fill: none; stroke: var(--d-networks); stroke-width: 2; stroke-linecap: round;
  animation: s-net-wave 2.6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .4s);
}
@keyframes s-net-wave { 0% { opacity: 0; } 30% { opacity: .7; } 100% { opacity: 0; } }

/* ISAC: one waveform out, a reflection back to the same radio */
.s-net__isac-out {
  fill: none; stroke: var(--a-amber); stroke-width: 1.6; opacity: .55;
  stroke-dasharray: 4 5; animation: s-net-isacline 2.4s linear infinite;
}
@keyframes s-net-isacline { to { stroke-dashoffset: -18; } }
.s-net__isac-back { fill: none; stroke: var(--a-amber-light); stroke-width: 1.4; opacity: .5; }
.s-net__tip { fill: var(--a-amber-light); }
.s-net__isac-target circle:first-child { fill: none; stroke: var(--a-amber); stroke-width: 2; }
.s-net__isac-echo {
  fill: none; stroke: var(--a-amber); stroke-width: 1.4;
  transform-box: fill-box; transform-origin: center;
  animation: s-net-echo 2.4s var(--ease) infinite;
}
@keyframes s-net-echo {
  0%, 100% { transform: scale(1); opacity: .8; }
  70%      { transform: scale(2.4); opacity: 0; }
}

/* ── devices ──────────────────────────────────────────────────────────── */
.s-net__device {
  fill: var(--dg-surface); stroke: var(--d-networks); stroke-width: 2.4;
  animation: s-net-device 4.5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .7s);
}
@keyframes s-net-device {
  0%, 76%, 100% { fill: var(--dg-surface); }
  8%, 22%       { fill: var(--d-networks-tint); }
}
.s-net__handover {
  fill: none; stroke: var(--d-automation); stroke-width: 1.6;
  opacity: .55; stroke-dasharray: 5 6;
  animation: s-net-handover 4s linear infinite;
}
@keyframes s-net-handover { to { stroke-dashoffset: -22; } }

/* ── edge, core and the slices between them ───────────────────────────── */
.s-net__edge, .s-net__core { fill: var(--dg-surface); stroke: var(--d-networks); stroke-width: 2; }
.s-net__label { fill: var(--dg-text); font-family: var(--f-sans); font-size: 13.5px; font-weight: var(--fw-semi); }
.s-net__sub   { fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 11px; }
.s-net__tag {
  fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 10.5px;
  letter-spacing: .06em; text-transform: uppercase;
  paint-order: stroke fill; stroke: var(--dg-surface); stroke-width: 5px; stroke-linejoin: round;
}

.s-net__slice { fill: none; stroke-width: 1.6; opacity: .45; }
.s-net__slice--a { stroke: var(--d-networks); }
.s-net__slice--b { stroke: var(--d-ai); }
.s-net__slice--c { stroke: var(--d-automation); }
.s-net__slice-pkt { offset-rotate: 0deg; animation: s-net-run 3.6s linear infinite; }
/* each slice carries at its own rate, which is the whole idea of slicing */
.s-net__slice-pkt--a { fill: var(--d-networks);   animation-duration: 2.6s; }
.s-net__slice-pkt--b { fill: var(--d-ai);         animation-duration: 3.8s; }
.s-net__slice-pkt--c { fill: var(--d-automation); animation-duration: 5.2s; }

.s-net__link { fill: none; stroke: var(--d-networks); stroke-width: 1.4; opacity: .22; }

@media (prefers-reduced-motion: reduce) {
  .s-net__ctrl-pkt, .s-net__sat, .s-net__beam, .s-net__d2d-pkt, .s-net__wave,
  .s-net__isac-out, .s-net__isac-echo, .s-net__device, .s-net__handover,
  .s-net__slice-pkt { animation: none; }
  .s-net__ctrl-pkt, .s-net__d2d-pkt, .s-net__slice-pkt { opacity: 1; offset-distance: 50%; }
  .s-net__sat { offset-distance: 40%; }
  .s-net__wave { opacity: .45; }
  .s-net__isac-echo { opacity: .4; }
}

}

/* ── diagram-neuro-symbolic.css ─────────────────────────── */
/* ── Neuro-symbolic validation diagram ───────────────────────────────────
   The rejected branch carries the same visual weight as the approved one,
   because the guarantee being described is that both exist. */
@layer sections {

.s-ns__box { fill: var(--dg-surface); stroke: var(--dg-line); stroke-width: 1.5; }
.s-ns__box--model { fill: var(--dg-surface-soft); stroke: var(--dg-line); }
.s-ns__box--rules { fill: var(--dg-surface); stroke: var(--c-azure); stroke-width: 2; }
.s-ns__box--ok    { fill: color-mix(in srgb, var(--s-valid) 10%, transparent); stroke: var(--s-valid); }
.s-ns__box--stop  { fill: color-mix(in srgb, var(--s-blocked) 10%, transparent); stroke: var(--s-blocked); }

.s-ns__title { fill: var(--dg-text); font-family: var(--f-sans); font-size: 15px; font-weight: var(--fw-semi); }
.s-ns__title--ok   { fill: var(--s-valid); }
.s-ns__title--stop { fill: var(--s-blocked); }
.s-ns__sub  { fill: var(--dg-text-muted);  font-family: var(--f-sans); font-size: 12.5px; }
.s-ns__rule { fill: var(--c-azure-text); font-family: var(--f-sans); font-size: 12.5px; font-weight: var(--fw-medium); }
.l-section--ink .s-ns__rule { fill: var(--c-azure-on-dark); }
.s-ns__gate {
  fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 10.5px;
  letter-spacing: .05em; text-transform: uppercase;
}
.s-ns__caption { fill: var(--dg-text-muted); font-family: var(--f-sans); font-size: 12.5px; }

.s-ns__wire { fill: none; stroke: var(--dg-line); stroke-width: 2; }
.s-ns__wire--ok   { stroke: color-mix(in srgb, var(--s-valid) 55%, transparent); }
.s-ns__wire--stop { stroke: color-mix(in srgb, var(--s-blocked) 55%, transparent); stroke-dasharray: 5 5; }

/* The packet must stay visible on both grounds. */
.s-ns__packet {
  fill: var(--c-azure); offset-rotate: 0deg;
  animation: s-ns-run 2.6s var(--ease) infinite;
}
@keyframes s-ns-run {
  0%   { offset-distance: 0%;   opacity: 0; }
  15%  { opacity: 1; }
  80%  { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .s-ns__packet { animation: none; opacity: 1; offset-distance: 50%; }
}

}

/* ── dna.css ─────────────────────────── */
/* ── Innovation DNA ───────────────────────────────────────────────────────
   Four principles, separated by space and a large quiet numeral rather than
   by cards. No borders, no boxes — this is the section that most needs to not
   look generated. */
@layer sections {

/* Three rows of subgrid — numeral, title, body — so a two-line title in one
   column keeps every column's body text on the same baseline. */
.s-dna__list {
  display: grid; gap: var(--sp-7) var(--sp-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  grid-auto-rows: auto auto auto;
}
.s-dna__item {
  display: grid; grid-template-rows: subgrid; grid-row: span 3;
  gap: var(--sp-3); align-content: start;
}
@supports not (grid-template-rows: subgrid) {
  .s-dna__item { display: block; }
}
.s-dna__n {
  display: block;
  font-size: 2.25rem; font-weight: var(--fw-semi); line-height: 1;
  letter-spacing: -.04em;
  color: color-mix(in srgb, var(--c-azure) 42%, transparent);
}
.s-dna__title { margin: 0; }
.s-dna__item p { font-size: var(--fs-small); color: var(--t-body); line-height: 1.6; }

}

/* ── domain-index.css ─────────────────────────── */
/* ── Technology index ─────────────────────────────────────────────────────
   Full-width rows, alternating, each carrying its domain's colour. This is
   the hub's own layout: repeating the homepage's pillar grid here would make
   the two pages read as the same page with different words. */
@layer sections {

.s-domains__list { display: grid; }

.s-domains__row {
  display: grid; align-items: center;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--sp-5) var(--sp-7);
  padding: var(--sp-6) 0;
  border-top: 1px solid var(--line);
  text-decoration: none; color: inherit;
  position: relative;
}
.s-domains__row:last-child { border-bottom: 1px solid var(--line); }

/* a wash of the domain's colour, drawn on hover from the side it sits on */
.s-domains__row::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg,
              color-mix(in srgb, var(--s-dom-hue) 7%, transparent), transparent 60%);
  opacity: 0; transition: opacity var(--dur-base) var(--ease);
  pointer-events: none;
}
.s-domains__row:hover::before { opacity: 1; }
.s-domains__row--flip::before { background: linear-gradient(270deg,
              color-mix(in srgb, var(--s-dom-hue) 7%, transparent), transparent 60%); }

.s-domains__index {
  font-family: var(--f-mono); font-size: var(--fs-small);
  color: var(--s-dom-hue); align-self: start; padding-top: .4rem;
}

.s-domains__body { display: grid; gap: var(--sp-4); max-width: 46rem; }
.s-domains__name {
  font-size: var(--fs-h3); font-weight: var(--fw-semi);
  letter-spacing: var(--ls-h3); line-height: var(--lh-heading);
}
.s-domains__row:hover .s-domains__name { color: var(--s-dom-hue); }
.s-domains__text { color: var(--t-body); }

/* terms as a delimited run, matching the rest of the site */
.s-domains__terms { display: flex; flex-wrap: wrap; font-size: var(--fs-small); color: var(--t-muted); }
.s-domains__terms span:not(:last-child)::after {
  content: "·"; margin: 0 var(--sp-3); color: var(--s-dom-hue); opacity: .6;
}
.s-domains__go {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-small); font-weight: var(--fw-semi); color: var(--s-dom-hue);
}
.s-domains__go::after { content: "→"; transition: transform var(--dur-fast) var(--ease); }
.s-domains__row:hover .s-domains__go::after { transform: translateX(4px); }

.s-domains__field { width: 11rem; justify-self: end; }
.s-domains__row--flip { grid-template-columns: auto minmax(0, 1fr) auto; }
.s-domains__row--flip .s-domains__field { order: -1; justify-self: start; }
.s-domains__row--flip .s-domains__index { order: -2; }

.s-domains__row--ai         { --s-dom-hue: var(--d-ai); }
.s-domains__row--automation { --s-dom-hue: var(--d-automation); }
.s-domains__row--robotics   { --s-dom-hue: var(--d-robotics); }
.s-domains__row--networks   { --s-dom-hue: var(--d-networks); }

@media (max-width: 60rem) {
  .s-domains__row,
  .s-domains__row--flip { grid-template-columns: auto minmax(0, 1fr); }
  .s-domains__field { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .s-domains__halo { animation: none; }
}

}

/* ── domain-marks.css ─────────────────────────── */
/* ── Domain marks ─────────────────────────────────────────────────────────
   One animated mark per technology domain, on the Technologies hub. Each
   shows the mechanism its paragraph describes — federated updates converging,
   a validated control loop, an agent sensing its surroundings, terrestrial
   and satellite coverage — rather than a generic pulsing ring.

   All four read the row's hue, so a domain's colour carries through its mark.
   All four stop entirely under prefers-reduced-motion. */
@layer sections {

.s-mark { width: 100%; height: auto; overflow: visible; }

/* shared parts */
.s-mark__wire  { fill: none; stroke: var(--s-dom-hue); stroke-width: 1.5; opacity: .25; stroke-dasharray: 3 4; }
.s-mark__track { fill: none; stroke: var(--s-dom-hue); stroke-width: 1.5; opacity: .28; stroke-dasharray: 3 6; }
.s-mark__core  { fill: var(--s-dom-hue); }
.s-mark__halo  {
  fill: none; stroke: var(--s-dom-hue); stroke-width: 1.5;
  transform-box: fill-box; transform-origin: center;
  animation: s-mark-breathe 3.6s var(--ease) infinite;
}
@keyframes s-mark-breathe {
  0%, 100% { transform: scale(1);    opacity: .4; }
  50%      { transform: scale(1.25); opacity: 0; }
}

.s-mark__packet { fill: var(--s-dom-hue); offset-rotate: 0deg;
  animation: s-mark-run 3s var(--ease) infinite; animation-delay: var(--d, 0s); }
@keyframes s-mark-run {
  0%   { offset-distance: 0%;   opacity: 0; }
  12%  { opacity: 1; }
  80%  { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* ── Advanced AI ──────────────────────────────────────────────────────── */
.s-mark__node {
  fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2;
  animation: s-mark-train 3s var(--ease) infinite;
  animation-delay: calc(var(--i) * .5s);
}
@keyframes s-mark-train {
  0%, 70%, 100% { fill: var(--dg-surface); }
  10%, 26%      { fill: var(--s-dom-hue); }
}

/* ── Automation ───────────────────────────────────────────────────────── */
.s-mark__arrow { fill: none; stroke: var(--s-dom-hue); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; opacity: .55; }
.s-mark__token { fill: var(--s-dom-hue); offset-rotate: 0deg;
  animation: s-mark-loop 4s var(--ease) infinite; }
/* it pauses at the gate: the check happens before the action continues */
@keyframes s-mark-loop {
  0%   { offset-distance: 0%; }
  8%   { offset-distance: 0%; }
  100% { offset-distance: 100%; }
}
.s-mark__gate { fill: var(--s-dom-hue); opacity: .3;
  animation: s-mark-gate 4s var(--ease) infinite; }
@keyframes s-mark-gate {
  0%, 6% { opacity: .95; }
  20%, 100% { opacity: .3; }
}
.s-mark__core--sm { fill: none; stroke: var(--s-dom-hue); stroke-width: 2; }
.s-mark__check { fill: none; stroke: var(--s-dom-hue); stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round; }

/* ── Robotics ─────────────────────────────────────────────────────────── */
.s-mark__sweep { transform-box: fill-box; transform-origin: 100px 100px;
  animation: s-mark-sweep 5s linear infinite; }
@keyframes s-mark-sweep { to { transform: rotate(360deg); } }
.s-mark__beam { fill: var(--s-dom-hue); opacity: .1; }
.s-mark__step {
  fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2;
  animation: s-mark-step 5s var(--ease) infinite;
  animation-delay: calc(var(--i) * 1s);
}
@keyframes s-mark-step {
  0%, 84%, 100% { fill: var(--dg-surface); }
  6%, 16%       { fill: var(--s-dom-hue); }
}
.s-mark__body { fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2; }
.s-mark__eye  { fill: var(--s-dom-hue); }
.s-mark__ant  { stroke: var(--s-dom-hue); stroke-width: 2; stroke-linecap: round; }

/* ── Networks ─────────────────────────────────────────────────────────── */
.s-mark__arc {
  fill: none; stroke: var(--s-dom-hue); stroke-width: 2; stroke-linecap: round;
  animation: s-mark-propagate 2.8s var(--ease) infinite;
  animation-delay: calc(var(--i) * .45s);
}
@keyframes s-mark-propagate {
  0%   { opacity: 0; }
  25%  { opacity: .75; }
  100% { opacity: 0; }
}
.s-mark__tower { fill: none; stroke: var(--s-dom-hue); stroke-width: 2.2; stroke-linecap: round; }
.s-mark__tip   { fill: var(--s-dom-hue); }
.s-mark__sat   { animation: s-mark-orbit 7s ease-in-out infinite; }
@keyframes s-mark-orbit {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(-14px, 8px); }
}
.s-mark__sat-body { fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2; }
.s-mark__sat-wing { stroke: var(--s-dom-hue); stroke-width: 2; stroke-linecap: round; }
.s-mark__link { fill: none; stroke: var(--s-dom-hue); stroke-width: 1.5; opacity: .25; stroke-dasharray: 4 5; }

@media (prefers-reduced-motion: reduce) {
  .s-mark__halo, .s-mark__packet, .s-mark__node, .s-mark__token,
  .s-mark__gate, .s-mark__sweep, .s-mark__step, .s-mark__arc,
  .s-mark__sat { animation: none; }
  .s-mark__packet { opacity: 1; offset-distance: 55%; }
  .s-mark__arc    { opacity: .5; }
  .s-mark__halo   { opacity: .35; }
}


/* ── Marks for the delivery and reference areas ──────────────────────────
   Every row on the Product & Service and Insights hubs has its own mark.
   Choosing by hue meant three rows shared one drawing, which read as a
   template rather than a set. All of these follow the same rules as the
   technology marks: one hue from the row, motion that shows what the row
   describes, and nothing moving under prefers-reduced-motion. */

/* Selected Projects: four lines of work, each advancing separately */
.s-mark__stem { stroke: var(--s-dom-hue); stroke-width: 1.4; opacity: .3; }
.s-mark__node {
  fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2.4;
  animation: s-mark-node 5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .5s);
}
@keyframes s-mark-node { 0%, 76%, 100% { fill: var(--dg-surface); } 8%, 22% { fill: var(--s-dom-hue); } }
.s-mark__trend {
  fill: none; stroke: var(--s-dom-hue); stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 160; stroke-dashoffset: 160;
  animation: s-mark-draw 5s var(--ease) infinite;
}
@keyframes s-mark-draw { 0% { stroke-dashoffset: 160; } 50%, 100% { stroke-dashoffset: 0; } }

/* Architecture & PoC: layers assembled, a build pulse rising through them */
.s-mark__layer {
  fill: none; stroke: var(--s-dom-hue); stroke-width: 2; opacity: .4;
  animation: s-mark-layer 4.5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .45s);
}
@keyframes s-mark-layer { 0%, 70%, 100% { opacity: .4; } 10%, 24% { opacity: 1; } }
.s-mark__spine { stroke: var(--s-dom-hue); stroke-width: 1.3; opacity: .25; stroke-dasharray: 3 5; }
.s-mark__build {
  fill: var(--s-dom-hue); offset-rotate: 0deg;
  animation: s-mark-run 4.5s var(--ease) infinite;
}

/* International R&D: partners converging on one project */
.s-mark__spoke { stroke: var(--s-dom-hue); stroke-width: 1.3; opacity: .25; }
.s-mark__partner {
  fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2;
  animation: s-mark-node 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .4s);
}
.s-mark__inbound {
  fill: var(--s-dom-hue); offset-rotate: 0deg;
  animation: s-mark-run 6s var(--ease) infinite;
  animation-delay: calc(var(--i) * .4s);
}
.s-mark__hub { fill: var(--s-dom-hue); }

/* Due diligence: a lens travelling across the evidence */
.s-mark__col {
  fill: var(--s-dom-hue); opacity: .35;
  transform-box: fill-box; transform-origin: center bottom;
  animation: s-mark-col 5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .18s);
}
@keyframes s-mark-col { 0%, 100% { transform: scaleY(1); } 50% { transform: scaleY(.62); } }
.s-mark__lens {
  animation: s-mark-lens 5s ease-in-out infinite alternate;
}
@keyframes s-mark-lens {
  from { transform: translate(66px, 96px); }
  to   { transform: translate(140px, 122px); }
}
.s-mark__lens-rim { fill: color-mix(in srgb, var(--s-dom-hue) 8%, transparent); stroke: var(--s-dom-hue); stroke-width: 2.6; }
.s-mark__lens-handle { stroke: var(--s-dom-hue); stroke-width: 4; stroke-linecap: round; }

/* Research: a source being read */
.s-mark__sheet { fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2; }
.s-mark__line {
  fill: var(--s-dom-hue); opacity: .35;
  transform-box: fill-box; transform-origin: left center;
  animation: s-mark-line 5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .25s);
}
@keyframes s-mark-line { 0%, 100% { transform: scaleX(1); opacity: .35; } 45% { transform: scaleX(.7); opacity: .7; } }
.s-mark__read {
  stroke: var(--a-amber); stroke-width: 2.4; stroke-linecap: round;
  animation: s-mark-read 5s var(--ease) infinite;
}
@keyframes s-mark-read {
  0%   { transform: translateY(0);   opacity: 0; }
  10%  { opacity: .9; }
  85%  { transform: translateY(86px); opacity: .9; }
  100% { transform: translateY(86px); opacity: 0; }
}

/* Standards: a specification, checked and sealed */
.s-mark__seal { fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2.4; }
.s-mark__seal-check {
  fill: none; stroke: var(--a-amber); stroke-width: 3;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 40; stroke-dashoffset: 40;
  animation: s-mark-seal 5s var(--ease) infinite;
}
@keyframes s-mark-seal { 0%, 30% { stroke-dashoffset: 40; } 55%, 100% { stroke-dashoffset: 0; } }

/* White papers: a stack, the top sheet lifting */
.s-mark__sheet--2 { opacity: .4; }
.s-mark__sheet--1 { opacity: .7; }
.s-mark__sheet--0 {
  animation: s-mark-lift 5s var(--ease) infinite;
}
@keyframes s-mark-lift {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(-6px, -8px); }
}

/* Briefs: short pieces, one highlighted at a time */
.s-mark__brief-box {
  fill: var(--dg-surface); stroke: var(--s-dom-hue); stroke-width: 2; opacity: .45;
  animation: s-mark-brief 5.4s var(--ease) infinite;
  animation-delay: calc(var(--i) * .6s);
}
@keyframes s-mark-brief { 0%, 72%, 100% { opacity: .45; } 8%, 24% { opacity: 1; } }

/* Courses: a path climbed step by step */
.s-mark__step-box {
  fill: var(--s-dom-hue); opacity: .22;
  transform-box: fill-box; transform-origin: center bottom;
  animation: s-mark-step-up 5.5s var(--ease) infinite;
  animation-delay: calc(var(--i) * .5s);
}
@keyframes s-mark-step-up { 0%, 80%, 100% { opacity: .22; } 10%, 26% { opacity: .55; } }
.s-mark__climb {
  fill: none; stroke: var(--s-dom-hue); stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round; opacity: .5;
}
.s-mark__learner {
  fill: var(--a-amber); offset-rotate: 0deg;
  animation: s-mark-climb 5.5s var(--ease) infinite;
}
@keyframes s-mark-climb {
  0%   { offset-distance: 0%;   opacity: 0; }
  10%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .s-mark__node, .s-mark__trend, .s-mark__layer, .s-mark__build,
  .s-mark__partner, .s-mark__inbound, .s-mark__col, .s-mark__lens,
  .s-mark__line, .s-mark__read, .s-mark__seal-check, .s-mark__sheet--0,
  .s-mark__brief-box, .s-mark__step-box, .s-mark__learner { animation: none; }
  .s-mark__trend, .s-mark__seal-check { stroke-dashoffset: 0; }
  .s-mark__build, .s-mark__inbound, .s-mark__learner { opacity: 1; offset-distance: 50%; }
  .s-mark__read { opacity: 0; }
  .s-mark__lens { transform: translate(100px, 108px); }
}

}

/* ── ecosystem.css ─────────────────────────── */
/* ── Collaboration ecosystem ──────────────────────────────────────────────
   Statement on the left, the list of partner types on the right as plain
   rows. Asymmetric on purpose: a centred grid here would read as filler. */
@layer sections {

.s-ecosystem__title { margin: var(--sp-5) 0 var(--sp-5); }
.s-ecosystem__lead  { color: var(--t-body); font-size: var(--fs-lead); line-height: 1.5; }

.s-ecosystem__list { display: grid; }
.s-ecosystem__list li {
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--line-warm);
  font-size: var(--fs-lead); font-weight: var(--fw-medium);
  letter-spacing: -.02em;
}
.s-ecosystem__list li:first-child { border-top: 1px solid var(--line-warm); }

}

/* ── experience.css ─────────────────────────── */
/* ── Experience ───────────────────────────────────────────────────────── */
@layer sections {

.s-experience__grid {
  display: grid; gap: var(--sp-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
}
.s-experience__name {
  padding-bottom: var(--sp-4); margin-bottom: var(--sp-5);
  border-bottom: 2px solid var(--c-azure-on-dark);
}
.s-experience__tags { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-4); }
.s-experience__tags li {
  font-size: var(--fs-small); color: var(--t-on-dark-body);
}
.s-experience__tags li::after { content: " ·"; color: var(--c-azure-on-dark); }
.s-experience__tags li:last-child::after { content: ""; }

}

/* ── explainer.css ─────────────────────────── */
/* ── Explainer ────────────────────────────────────────────────────────────
   Prose beside a diagram. The pull points and the "why it matters" block give
   the column three distinct textures, so a long technical page keeps a
   rhythm instead of turning into a wall. */
@layer sections {

.s-explainer__text { max-width: 34rem; }
/* Full section width, capped at a comfortable measure so it reads in two
   lines rather than five. */
.s-explainer__title { max-width: 34ch; margin: 0 0 var(--sp-6); }
.s-explainer__prose p { color: var(--t-body); }
.s-explainer__prose p + p { margin-top: 1em; }
.l-section--ink .s-explainer__prose p { color: var(--t-on-dark-body); }

.s-explainer__pull { margin: var(--sp-5) 0 0; }
.s-explainer__pull li {
  position: relative; padding-left: var(--sp-6); margin-top: var(--sp-3);
  font-weight: var(--fw-medium); color: var(--t-strong); line-height: 1.5;
}
.l-section--ink .s-explainer__pull li { color: var(--t-on-dark); }
.s-explainer__pull li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 14px; height: 2px; border-radius: 2px;
  background: var(--c-azure);
}

.s-explainer__why {
  margin-top: var(--sp-7); padding-top: var(--sp-5);
  border-top: 2px solid var(--a-amber);
}
.s-explainer__why-label {
  display: block; margin-bottom: var(--sp-2);
  font-size: var(--fs-eyebrow); font-weight: var(--fw-semi);
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase;
  color: var(--a-amber-deep);
}
.l-section--ink .s-explainer__why-label { color: var(--a-amber-light); }
.s-explainer__why p { font-size: var(--fs-lead); line-height: 1.45; color: var(--t-strong); }
.l-section--ink .s-explainer__why p { color: var(--t-on-dark); }

.s-explainer__figure svg { width: 100%; height: auto; }

/* Stacked: the prose keeps a reading width, the diagram takes the whole
   container. A wide technical figure needs the room, and this is also what
   stops a large monitor showing a narrow column with empty sides. */
.s-explainer__stack { display: grid; gap: var(--sp-6); }
.s-explainer__stack .s-explainer__text { max-width: var(--w-read); }

/* Where a stacked section has an aside, the two sit side by side and fill
   the width. Without this the prose ran at reading width down the left and
   the right half of the section stayed empty. */
@media (min-width: 66rem) {
  .s-explainer__stack .s-explainer__text:has(.s-explainer__aside) {
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--sp-6) var(--sp-9);
    align-items: start;
  }
  .s-explainer__stack .s-explainer__prose { max-width: var(--w-read); }
  /* the aside's rule aligns with the first line of prose beside it */
  .s-explainer__stack .s-explainer__aside .s-explainer__pull { margin-top: 0; }
  .s-explainer__stack .s-explainer__aside .s-explainer__why:first-child { margin-top: 0; }
}
.s-explainer__stack .s-explainer__title { max-width: 40ch; }
/* Capped and centred. Left uncapped, a stacked diagram rendered at roughly
   twice the size of the same diagram in a split section, which made the two
   layouts look like two different sites. */
.s-explainer__stack .s-explainer__figure { width: 100%; max-width: 58rem; margin-inline: auto; }

}

/* ── footer.css ─────────────────────────── */
/* ── Site footer ──────────────────────────────────────────────────────── */
@layer sections {

.c-footer {
  background: var(--c-ink); color: var(--t-on-dark-body);
  padding-block: var(--sp-3) var(--sp-2);
}
/* One compact row for the brand — logo and tagline side by side — instead of
   a stacked block. Stacking cost a whole band of height for one logo and one
   sentence, and a narrow brand column forced the tagline to wrap. */
.c-footer__inner { display: grid; gap: var(--sp-2); }

/* The tagline is one sentence and should read as one line; at 28rem it broke
   after "next-", which reads as a typo rather than a wrap. */
.c-footer__brand { max-width: none; }
@media (min-width: 52rem) {
  .c-footer__brand {
    display: flex; align-items: center; gap: var(--sp-5);
    padding-bottom: var(--sp-2);
  }
  .c-footer__brand svg { margin-bottom: 0; flex-shrink: 0; }
  .c-footer__brand p { white-space: nowrap; }
}
.c-footer__brand svg { width: 6.5rem; height: auto; margin-bottom: var(--sp-3); display: block; }
.c-footer__brand p { color: var(--t-on-dark-body); font-size: var(--fs-small); line-height: 1.6; }

.c-footer__cols {
  display: grid; gap: var(--sp-7);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 8.5rem), 1fr));
}
.c-footer__heading {
  font-size: var(--fs-eyebrow); font-weight: var(--fw-semi);
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase;
  color: var(--t-on-dark); margin-bottom: var(--sp-2);
}
.c-footer__col li + li { margin-top: 3px; }
.c-footer__col a {
  font-size: var(--fs-small); color: var(--t-on-dark-body); text-decoration: none;
  transition: color var(--dur-fast) var(--ease);
}
.c-footer__col a:hover { color: var(--t-on-dark); }
/* the page you are on: shown, but not offered as a link */
.c-footer__col .is-current {
  font-size: var(--fs-small); color: var(--t-on-dark); font-weight: var(--fw-medium);
}

/* The site's single call to action lives in the footer instead of in a full
   dark band above it on every page. It sits on the same line as the first
   contact address rather than below the column. */
/* baseline, so the button's label sits on the same line as the first
   address rather than a few pixels off it */
.c-footer__contact { display: flex; align-items: baseline; gap: var(--sp-5); }
.c-footer__cta { flex-shrink: 0; padding: var(--sp-2) var(--sp-5); font-size: var(--fs-small); }

.c-footer__bottom {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: var(--sp-4) var(--sp-6);
  padding-top: var(--sp-2); border-top: 1px solid var(--line-on-dark);
}
.c-footer__legal { font-size: var(--fs-small); color: var(--t-on-dark-muted); }
.c-footer__legal-links { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); }
.c-footer__legal-links a {
  font-size: var(--fs-small); color: var(--t-on-dark-muted); text-decoration: none;
}
.c-footer__legal-links a:hover { color: var(--t-on-dark); }

}

/* ── header.css ─────────────────────────── */
/* ── Site header ──────────────────────────────────────────────────────── */
@layer sections {

.c-header {
  position: sticky; top: 0; z-index: var(--z-header);
  background: color-mix(in srgb, var(--g-paper) 88%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-base) var(--ease);
}
.c-header.is-scrolled { border-bottom-color: var(--line); }

.c-header__inner {
  display: flex; align-items: center; gap: var(--sp-6);
  min-height: 4.5rem;
}
.c-header__logo { display: flex; flex-shrink: 0; }
.c-header__logo svg { width: 7.5rem; height: auto; display: block; }

.c-nav { margin-left: auto; }
.c-nav__list { display: flex; align-items: center; gap: var(--sp-5); }
.c-nav__item { position: relative; }

/* inline-flex, not block: as a block the caret was treated as its own line
   box and dropped underneath the label */
.c-nav__link {
  display: inline-flex; align-items: center; gap: 5px;
  white-space: nowrap;
  padding-block: var(--sp-3);
  font-size: var(--fs-small); font-weight: var(--fw-medium);
  color: var(--t-body); text-decoration: none;
  transition: color var(--dur-fast) var(--ease);
}
.c-nav__link:hover { color: var(--c-ink); }

/* A caret marks the items that open a submenu. Without it there is nothing
   telling a visitor the item can be expanded. */
.c-nav__caret {
  width: 9px; height: 6px; flex-shrink: 0;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: .55;
  transition: transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.c-nav__item--has-menu:hover .c-nav__caret,
.c-nav__item--has-menu:focus-within .c-nav__caret { transform: rotate(180deg); opacity: 1; }
/* Copper marks where you are, the same way it marks what to click */
.c-nav__link.is-active { color: var(--a-amber-deep); font-weight: var(--fw-semi); }

/* Dropdown */
.c-nav__menu {
  position: absolute; top: 100%; left: calc(-1 * var(--sp-4)); min-width: 20rem;
  padding: var(--sp-3); background: var(--g-paper);
  border-radius: var(--r-md); box-shadow: var(--el-2);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease),
              visibility var(--dur-fast);
}
.c-nav__item--has-menu:hover .c-nav__menu,
.c-nav__item--has-menu:focus-within .c-nav__menu {
  opacity: 1; visibility: visible; transform: none;
}
.c-nav__sublink {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm);
  font-size: var(--fs-small); color: var(--t-body); text-decoration: none;
  transition: background var(--dur-fast) var(--ease);
}
.c-nav__sublink:hover { background: var(--g-mist); color: var(--c-ink); }
.c-nav__sublink.is-current { color: var(--a-amber-deep); font-weight: var(--fw-semi); cursor: default; }

/* Third level: the four projects under Selected Projects. Indented under
   their parent and marked with a rule, so the hierarchy is readable without
   another nested panel. */
.c-nav__subsub {
  margin: 0 0 var(--sp-2) calc(var(--sp-4) + 8px + var(--sp-3));
  padding-left: var(--sp-4);
  border-left: 1px solid var(--line);
}
.c-nav__leaflink {
  display: block; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  font-size: 12.5px; line-height: 1.35; color: var(--t-muted);
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.c-nav__leaflink:hover { background: var(--g-mist); color: var(--c-ink); }
.c-nav__leaflink.is-current { color: var(--a-amber-deep); font-weight: var(--fw-semi); cursor: default; }

/* the panel needs room for three levels */
.c-nav__item--has-menu .c-nav__menu { min-width: 24rem; }
span.c-nav__link { cursor: default; }

/* The pillar's hue, so the menu shows the colour coding the pages use */
.c-nav__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.c-nav__dot--ai         { background: var(--d-ai); }
.c-nav__dot--automation { background: var(--d-automation); }
.c-nav__dot--robotics   { background: var(--d-robotics); }
.c-nav__dot--networks   { background: var(--d-networks); }

.c-nav__toggle { display: none; background: none; border: 0; cursor: pointer; padding: var(--sp-3); }


/* ── Mobile ─────────────────────────────────────────────────────────── */
@media (max-width: 64rem) {
  .c-nav__toggle { display: block; }
  .c-nav__bars,
  .c-nav__bars::before,
  .c-nav__bars::after {
    display: block; width: 22px; height: 2px; border-radius: 2px;
    background: var(--c-ink); transition: transform var(--dur-base) var(--ease);
  }
  .c-nav__bars::before, .c-nav__bars::after { content: ""; position: relative; }
  .c-nav__bars::before { top: -7px; }
  .c-nav__bars::after  { top: 5px; }
  [aria-expanded="true"] .c-nav__bars { background: transparent; }
  [aria-expanded="true"] .c-nav__bars::before { transform: translateY(7px) rotate(45deg); }
  [aria-expanded="true"] .c-nav__bars::after  { transform: translateY(-5px) rotate(-45deg); }

  .c-nav__list {
    position: fixed; inset: 4.5rem 0 auto; z-index: var(--z-menu);
    flex-direction: column; align-items: stretch; gap: 0;
    padding: var(--sp-4) var(--gutter) var(--sp-8);
    background: var(--g-paper); border-bottom: 1px solid var(--line);
    max-height: calc(100dvh - 4.5rem); overflow-y: auto;
    display: none;
  }
  .c-nav__list.is-open { display: flex; }
  .c-nav__link { padding-block: var(--sp-4); font-size: var(--fs-body); }
  .c-nav__menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; padding: 0 0 var(--sp-4) var(--sp-4); min-width: 0;
  }
}

}

/* ── hero-home.css ─────────────────────────── */
/* ── Home hero ────────────────────────────────────────────────────────────
   Light, by the CEO's note N4. The only decoration is a soft azure glow
   behind the title — depth without a box. */
@layer sections {

.s-hero { padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem) 0; overflow: hidden; }

.s-hero__inner { text-align: center; position: relative; }

.s-hero__glow {
  position: absolute; top: -22rem; left: 50%; transform: translateX(-50%);
  width: min(72rem, 130vw); aspect-ratio: 11 / 7; border-radius: 50%;
  background: radial-gradient(closest-side,
              color-mix(in srgb, var(--c-azure) 15%, transparent),
              transparent);
  pointer-events: none;
}

.s-hero__title { max-width: 20ch; margin: var(--sp-4) auto var(--sp-5); }

.s-hero__lead {
  max-width: 36ch; margin-inline: auto;
  font-size: var(--fs-lead); line-height: 1.45; color: var(--t-body);
  letter-spacing: -.015em;
}
.s-hero__support {
  max-width: 60ch; margin: var(--sp-5) auto 0; color: var(--t-body);
}
.s-hero__actions { margin-top: var(--sp-8); justify-content: center; }

/* The technology strip: proof of range, read as a quiet line rather than a
   row of tags — tags would turn it into another box grid. */
/* A run of capability terms, delimited rather than boxed. Pills read as
   buttons and invite a click that does not exist. */
.s-hero__strip {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--sp-2) 0;
  margin-top: clamp(2rem, 1.25rem + 2.5vw, 3.25rem);
  padding-block: var(--sp-5);
  border-top: 1px solid var(--line);
}
.s-hero__strip li {
  font-size: var(--fs-small); color: var(--t-muted); white-space: nowrap;
}
.s-hero__strip li:not(:last-child)::after {
  content: "·"; margin: 0 var(--sp-4); color: var(--c-azure); opacity: .55;
}

}

/* ── hero-page.css ─────────────────────────── */
/* ── Page opener ──────────────────────────────────────────────────────── */
@layer sections {

.s-hero-page { padding-top: clamp(2rem, 1.5rem + 1.8vw, 3.25rem); }
.s-hero-page__title { margin: var(--sp-4) 0 var(--sp-4); max-width: 22ch; }
.s-hero-page__lead {
  font-size: var(--fs-lead); line-height: 1.5; color: var(--t-body);
}
/* Same treatment as the home strip: a delimited run of terms, not pills. */
/* Centred opener, used on the technology and project pages: the title and
   the sentence under it read as one centred block rather than a left-aligned
   column floating in the middle of the page. */
.s-hero-page--center { text-align: center; }
/* The block's reading cap is lifted here and applied to the heading and the
   sentence separately, so a short title is not forced to wrap at the
   paragraph's measure. */
.s-hero-page--center .s-hero-page__block { max-width: none; margin-inline: auto; }
.s-hero-page--center .s-hero-page__title { max-width: 22ch; margin-inline: auto; }
.s-hero-page--center .s-hero-page__lead  { max-width: 46ch; margin-inline: auto; }
.s-hero-page--center .s-hero-page__strip { justify-content: center; }

.s-hero-page__strip {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) 0;
  margin-top: var(--sp-6); padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
}
.s-hero-page__strip li {
  font-size: var(--fs-small); color: var(--t-muted); white-space: nowrap;
}
.s-hero-page__strip li:not(:last-child)::after {
  content: "·"; margin: 0 var(--sp-4); color: var(--c-azure); opacity: .55;
}

}

/* ── initiatives.css ─────────────────────────── */
/* ── R&D initiatives ──────────────────────────────────────────────────────
   A two-column list separated by hairlines, not four cards. The maturity
   label does the work of distinguishing them, so the layout does not have to. */
@layer sections {

.s-initiatives__list {
  display: grid; gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr));
  grid-auto-rows: auto auto auto auto;
  column-gap: var(--sp-8);
  border-top: 1px solid var(--line);
}
.s-initiatives__item {
  padding: var(--sp-6) 0;
  border-bottom: 1px solid var(--line);
  position: relative;
  /* rows align on their own internal lines regardless of title length */
  display: grid; grid-template-rows: subgrid; grid-row: span 4;
  align-content: start; gap: var(--sp-4);
  /* grid children stretch by default, which turned the maturity label from a
     pill hugging its text into a full-width bar */
  justify-items: start;
}
.s-initiatives__item > * { max-width: 100%; }
@supports not (grid-template-rows: subgrid) {
  .s-initiatives__item { display: block; }
}
/* The hue arrives as a short mark at the top edge, not as a filled box */
.s-initiatives__item::before {
  content: ""; position: absolute; top: -1px; left: 0;
  width: 3.5rem; height: 2px; background: var(--s-init-hue);
}
.s-initiatives__item--ai         { --s-init-hue: var(--d-ai); }
.s-initiatives__item--automation { --s-init-hue: var(--d-automation); }
.s-initiatives__item--robotics   { --s-init-hue: var(--d-robotics); }
.s-initiatives__item--networks   { --s-init-hue: var(--d-networks); }

.s-initiatives__title { margin: 0; max-width: 26ch; }
.s-initiatives__title a { color: inherit; text-decoration: none; }
.s-initiatives__title a:hover { color: var(--s-init-hue); }
/* the whole row is the target, not just the heading text */
.s-initiatives__title a::after { content: ""; position: absolute; inset: 0; }
.s-initiatives__text  { color: var(--t-body); max-width: 46ch; }
.s-initiatives__tech  {
  margin: 0; font-size: var(--fs-small); color: var(--t-muted);
}
.s-initiatives__actions { margin-top: var(--sp-6); }

.s-initiatives__facts {
  display: grid; gap: var(--sp-3) var(--sp-6); margin-top: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 8rem), 1fr));
}
.s-initiatives__facts dt {
  font-size: var(--fs-eyebrow); font-weight: var(--fw-semi);
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase;
  color: var(--t-muted); margin-bottom: 2px;
}
.s-initiatives__facts dd { margin: 0; font-size: var(--fs-small); color: var(--t-strong); }

.s-initiatives__pending { margin-top: var(--sp-5); }

}

/* ── maturity.css ─────────────────────────── */
/* ── Technology maturity ──────────────────────────────────────────────── */
@layer sections {

.s-maturity__list {
  display: grid; gap: var(--sp-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
.s-maturity__item dt { margin-bottom: var(--sp-4); }
.s-maturity__item dd {
  margin: 0; font-size: var(--fs-small); color: var(--t-body); line-height: 1.6;
}

}

/* ── partners.css ─────────────────────────── */
/* ── Partner marquee ──────────────────────────────────────────────────────
   One row, right to left, looping. The track holds two identical copies and
   travels exactly -50%, so the reset is invisible.

   Motion here is decorative rather than explanatory, so it pauses on hover
   and stops completely under prefers-reduced-motion, where the row becomes a
   normal horizontally scrollable list. */
@layer sections {

.s-partners__marquee {
  margin-top: var(--sp-6);
  overflow: hidden;
  /* fade the edges so logos enter and leave rather than being cut off */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.s-partners__track {
  display: flex; width: max-content;
  animation: s-partners-run 46s linear infinite;
}
.s-partners__marquee:hover .s-partners__track { animation-play-state: paused; }
@keyframes s-partners-run { to { transform: translateX(-50%); } }

.s-partners__row {
  display: flex; align-items: center;
  gap: var(--sp-9);
  padding-right: var(--sp-8);
}
/* Width follows the logo rather than a fixed slot: these lockups range from
   square to nearly 3:1, and a fixed slot shrank the wide ones to nothing. */
.s-partners__item {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
}
/* Full colour, always: these are the partners' own marks and they are shown
   as they are. 15% larger than before, at the client's request. */
.s-partners__item img {
  height: 3.45rem; width: auto; max-width: 15rem; object-fit: contain;
}
.s-partners__item .c-placeholder { width: 100%; min-height: 5.5rem; }

.s-partners__note {
  margin-top: var(--sp-5); text-align: center;
  font-size: var(--fs-eyebrow); color: var(--t-muted);
}

@media (prefers-reduced-motion: reduce) {
  .s-partners__track { animation: none; }
  .s-partners__marquee { overflow-x: auto; }
  /* the duplicate row is decoration; without motion it is just repetition */
  .s-partners__row[aria-hidden="true"] { display: none; }
}

}

/* ── pillars.css ─────────────────────────── */
/* ── Technology pillars ───────────────────────────────────────────────────
   Deliberately not cards. Each pillar is separated by a hairline in its own
   hue and by space — the rejected drafts made this a grid of identical
   rounded boxes, which is exactly the look being avoided. */
@layer sections {

.s-pillars__grid {
  display: grid; gap: var(--sp-7) var(--sp-7);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr));
}

.s-pillars__item {
  display: block; text-decoration: none; color: inherit;
  padding-top: var(--sp-5);
}
.s-pillars__rule {
  display: block; height: 2px; width: 3.5rem; margin-bottom: var(--sp-5);
  background: var(--s-pillars-hue);
  transition: width var(--dur-base) var(--ease);
}
.s-pillars__item:hover .s-pillars__rule { width: 6rem; }

/* Arrival: the rule draws out from nothing, so the hue introduces the pillar */
.s-pillars__item.is-pending { opacity: 0; transform: translateY(16px); }
.s-pillars__item.is-revealed .s-pillars__rule {
  animation: s-pillars-rule .75s var(--ease-out) .15s backwards;
}
@keyframes s-pillars-rule { from { width: 0; } }
@media (prefers-reduced-motion: reduce) {
  .s-pillars__item.is-revealed .s-pillars__rule { animation: none; }
}

.s-pillars__title { margin-bottom: var(--sp-4); }
.s-pillars__item:hover .s-pillars__title { color: var(--s-pillars-hue); }
.s-pillars__text { color: var(--t-body); margin-bottom: var(--sp-5); }

.s-pillars__list { margin-bottom: var(--sp-5); }
.s-pillars__list li {
  position: relative; padding-left: var(--sp-5);
  font-size: var(--fs-small); color: var(--t-body); line-height: 1.95;
}
.s-pillars__list li::before {
  content: ""; position: absolute; left: 0; top: .82em;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--s-pillars-hue); opacity: .55;
}

.s-pillars__go {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-small); font-weight: var(--fw-semi);
  color: var(--s-pillars-hue);
  transition: gap var(--dur-fast) var(--ease);
}
.s-pillars__go::after { content: "→"; }
.s-pillars__item:hover .s-pillars__go { gap: var(--sp-3); }

/* One hue per pillar, set once and read by every rule above */
.s-pillars__item--ai         { --s-pillars-hue: var(--d-ai); }
.s-pillars__item--automation { --s-pillars-hue: var(--d-automation); }
.s-pillars__item--robotics   { --s-pillars-hue: var(--d-robotics); }
.s-pillars__item--networks   { --s-pillars-hue: var(--d-networks); }

}

/* ── process.css ─────────────────────────── */
/* ── Idea to funded project ───────────────────────────────────────────────
   A vertical spine with a node per stage. Reads as one continuous pipeline
   rather than seven separate blocks, which is the point being made. */
@layer sections {

/* On a wide screen the heading sits beside the steps rather than above them.
   Stacked, this section filled only the left third of a large monitor and
   left the right side empty — the wide-display problem the CEO raised. */
@media (min-width: 66rem) {
  .s-process__inner {
    display: grid;
    grid-template-columns: minmax(0, 27rem) minmax(0, 1fr);
    gap: var(--sp-8);
    align-items: start;
  }
  .s-process__head {
    margin-bottom: 0;
    position: sticky; top: 6rem;
  }
}

.s-process__list { display: grid; }

.s-process__step { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-5); }

.s-process__marker {
  position: relative; width: 1rem;
  display: flex; justify-content: center;
}
/* the spine, drawn between nodes and stopped at the ends */
.s-process__marker::before {
  content: ""; position: absolute; top: 0; bottom: 0; width: 2px;
  background: color-mix(in srgb, var(--c-azure) 24%, transparent);
}
.s-process__step:first-child .s-process__marker::before { top: .85rem; }
.s-process__step:last-child  .s-process__marker::before { bottom: calc(100% - .85rem); }

.s-process__dot {
  position: relative; margin-top: .6rem;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--g-mist); border: 2.5px solid var(--c-azure);
}

.s-process__body { padding-bottom: var(--sp-6); }
.s-process__title {
  display: flex; align-items: baseline; gap: var(--sp-4);
  margin-bottom: var(--sp-2);
}
.s-process__n {
  font-size: var(--fs-eyebrow); font-weight: var(--fw-semi);
  letter-spacing: var(--ls-eyebrow); color: var(--t-muted);
}
.s-process__body p { color: var(--t-body); max-width: 54ch; font-size: var(--fs-small); }

/* Arrival: the spine grows downward through each stage and the node fills as
   it is reached — the animation is the pipeline it describes. */
.s-process__step.is-pending { opacity: 0; transform: translateY(16px); }

.s-process__step.is-revealed .s-process__marker::before {
  transform-origin: top;
  animation: s-process-spine .55s var(--ease-out) backwards;
}
@keyframes s-process-spine { from { transform: scaleY(0); } }

.s-process__step.is-revealed .s-process__dot {
  animation: s-process-dot .45s var(--ease-out) .2s backwards;
}
@keyframes s-process-dot {
  from { transform: scale(.2); background: var(--c-azure); }
}

@media (prefers-reduced-motion: reduce) {
  .s-process__step.is-revealed .s-process__marker::before,
  .s-process__step.is-revealed .s-process__dot { animation: none; }
}

}

/* ── project-hero.css ─────────────────────────── */
/* ── Project page opener ──────────────────────────────────────────────────
   Carries its project's hue so the four pages are distinguishable at a
   glance, and puts the maturity label above the title so a reader knows what
   they are looking at before they read the claim. */
@layer sections {

.s-project-hero { padding-top: clamp(2.5rem, 2rem + 3vw, 4rem); }

.s-project-hero__back {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  margin-bottom: var(--sp-6);
  font-size: var(--fs-small); font-weight: var(--fw-medium);
  color: var(--s-proj-hue); text-decoration: none;
}
.s-project-hero__back::before { content: "←"; }
.s-project-hero__back:hover { text-decoration: underline; }

.s-project-hero__title { margin: var(--sp-4) 0 var(--sp-4); }
.s-project-hero__lead {
  font-size: var(--fs-lead);
  line-height: 1.5; color: var(--t-body);
}

.s-project-hero__terms {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) 0;
  margin-top: var(--sp-7); padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
}
.s-project-hero__terms li { font-size: var(--fs-small); color: var(--t-muted); white-space: nowrap; }
.s-project-hero__terms li:not(:last-child)::after {
  content: "·"; margin: 0 var(--sp-4); color: var(--s-proj-hue); opacity: .6;
}

.s-project-hero--ai         { --s-proj-hue: var(--d-ai); }
.s-project-hero--automation { --s-proj-hue: var(--d-automation); }
.s-project-hero--robotics   { --s-proj-hue: var(--d-robotics); }
.s-project-hero--networks   { --s-proj-hue: var(--d-networks); }

/* Centred opener, matching the technology pages. */
.s-project-hero--center { text-align: center; }
.s-project-hero--center .s-project-hero__block { margin-inline: auto; }
.s-project-hero--center .s-project-hero__title { max-width: none; }
.s-project-hero--center .s-project-hero__lead  { max-width: none; }
.s-project-hero--center .s-project-hero__terms { justify-content: center; }
.s-project-hero--center .s-project-hero__back  { }

.s-project-facts__title { margin-bottom: var(--sp-6); font-size: var(--fs-h3); }
.s-project-facts .c-placeholder { max-width: 42rem; }

}

/* ── prose.css ─────────────────────────── */
/* ── Prose page ───────────────────────────────────────────────────────── */
@layer sections {

.s-prose__body > * + * { margin-top: var(--sp-5); }
.s-prose__body h2 { margin-top: var(--sp-8); font-size: var(--fs-h3); }
.s-prose__body p { color: var(--t-body); }
.s-prose__list { margin-top: var(--sp-4); }
.s-prose__list li {
  position: relative; padding-left: var(--sp-5); margin-top: var(--sp-3);
  color: var(--t-body);
}
.s-prose__list li::before {
  content: ""; position: absolute; left: 0; top: .72em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--c-azure);
}

}

/* ── related.css ─────────────────────────── */
/* ── Related ──────────────────────────────────────────────────────────── */
@layer sections {

.s-related__title {
  font-size: var(--fs-eyebrow); font-weight: var(--fw-semi);
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase;
  color: var(--t-muted); margin-bottom: var(--sp-5);
}
.s-related__list {
  display: grid; gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}
.s-related__link {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-5) var(--sp-5) 0;
  border-top: 2px solid var(--s-rel-hue);
  text-decoration: none; color: var(--t-strong);
  font-weight: var(--fw-medium); letter-spacing: -.015em;
  transition: color var(--dur-fast) var(--ease);
}
.s-related__link:hover { color: var(--s-rel-hue); }
.s-related__go { color: var(--s-rel-hue); transition: transform var(--dur-fast) var(--ease); }
.s-related__link:hover .s-related__go { transform: translateX(4px); }

.s-related__link--ai         { --s-rel-hue: var(--d-ai); }
.s-related__link--automation { --s-rel-hue: var(--d-automation); }
.s-related__link--robotics   { --s-rel-hue: var(--d-robotics); }
.s-related__link--networks   { --s-rel-hue: var(--d-networks); }
.s-related__link--neutral    { --s-rel-hue: var(--c-blue); }

}

/* ── resources.css ─────────────────────────── */
/* ── Selected research & resources ───────────────────────────────────────
   A ruled list, matching the standards section directly above it, with the
   subject area carried in the left column so a reader can scan by topic
   rather than by publisher. */
@layer sections {

.s-resources__list { display: grid; border-top: 1px solid var(--line); }

.s-resources__item {
  display: grid; gap: var(--sp-2) var(--sp-7);
  grid-template-columns: minmax(0, 1fr);
  padding: var(--sp-5) 0;
  border-bottom: 1px solid var(--line);
}
@media (min-width: 56rem) {
  .s-resources__item { grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); }
}

.s-resources__area {
  font-size: var(--fs-eyebrow); font-weight: var(--fw-semi);
  letter-spacing: .05em; text-transform: uppercase;
  color: var(--s-res-hue);
}
.s-resources__name {
  display: inline-block; margin-bottom: var(--sp-2);
  font-weight: var(--fw-semi); color: var(--c-blue);
  text-decoration: none; letter-spacing: -.015em;
}
.s-resources__name:hover { color: var(--c-ink); text-decoration: underline; }
.s-resources__ext { margin-left: .3em; font-size: .85em; opacity: .7; }
.s-resources__why { font-size: var(--fs-small); color: var(--t-body); line-height: 1.6; max-width: 62ch; }
.s-resources__source {
  display: inline-block; margin-top: var(--sp-2);
  font-size: var(--fs-eyebrow); color: var(--t-muted);
}

.s-resources__list--ai         { --s-res-hue: var(--d-ai); }
.s-resources__list--automation { --s-res-hue: var(--d-automation); }
.s-resources__list--robotics   { --s-res-hue: var(--d-robotics); }
.s-resources__list--networks   { --s-res-hue: var(--d-networks); }

}

/* ── reveal.css ─────────────────────────── */
/* ── Scroll choreography ──────────────────────────────────────────────────
   The base state. A section may override what `is-revealed` does — the point
   is that arriving is not always a fade, so the page does not feel like one
   template repeating.

   The pending state is applied by JavaScript, never in the markup, so content
   stays visible if the script fails, is blocked, or never runs. */
@layer utilities {

[data-reveal],
[data-stagger] > * {
  transition:
    opacity   var(--dur-slow) var(--ease-out) var(--reveal-delay, 0ms),
    transform var(--dur-slow) var(--ease-out) var(--reveal-delay, 0ms);
}

[data-reveal].is-pending,
[data-stagger] > .is-pending {
  opacity: 0;
  transform: translateY(16px);
}

[data-reveal].is-revealed,
[data-stagger] > .is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal].is-pending,
  [data-stagger] > .is-pending { opacity: 1; transform: none; }
}

}

/* ── services.css ─────────────────────────── */
/* ── Advisory services ────────────────────────────────────────────────── */
@layer sections {

.s-services__list {
  display: grid; gap: var(--sp-6) var(--sp-7);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  counter-reset: service;
}
.s-services__item { counter-increment: service; position: relative; padding-top: var(--sp-6); }
.s-services__item::before {
  content: counter(service, decimal-leading-zero);
  position: absolute; top: 0; left: 0;
  font-family: var(--f-mono); font-size: var(--fs-small);
  color: var(--c-azure-text);
}
.s-services__name { margin-bottom: var(--sp-3); }
.s-services__item p { font-size: var(--fs-small); color: var(--t-body); line-height: 1.6; }

}

/* ── standards.css ─────────────────────────── */
/* ── Selected standards ───────────────────────────────────────────────── */
@layer sections {

.s-standards__list { display: grid; gap: 0; border-top: 1px solid var(--line); }
.s-standards__item {
  display: grid; gap: var(--sp-2) var(--sp-8);
  grid-template-columns: minmax(0, 1fr);
  padding: var(--sp-6) 0;
  border-bottom: 1px solid var(--line);
}
@media (min-width: 56rem) {
  .s-standards__item { grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); align-items: baseline; }
}
.s-standards__name {
  font-weight: var(--fw-semi); color: var(--c-blue);
  text-decoration: none; letter-spacing: -.015em;
}
a.s-standards__name:hover { color: var(--c-ink); text-decoration: underline; }
.s-standards__ext { margin-left: .3em; font-size: .85em; opacity: .7; }
.s-standards__why { font-size: var(--fs-small); color: var(--t-body); line-height: 1.6; }
/* Inline with the sentence it qualifies, not a block beneath it. */
.s-standards__status {
  font-weight: var(--fw-semi);
  letter-spacing: .04em; text-transform: uppercase;
  font-size: .82em; color: var(--a-amber-deep);
  white-space: nowrap;
}
.l-section--ink .s-standards__status { color: var(--a-amber-light); }

}

/* ── toc.css ─────────────────────────── */
/* ── Floating table of contents ───────────────────────────────────────────
   A position map for the long technical pages. Each entry fills with its
   section's colour as the reader moves through it and empties again on the
   way back up, so the rail always reflects where they are.

   The rail is fixed, so the page has to give it room: without reserved space
   it sits on top of the content and becomes unreadable the moment it crosses
   a dark band. Below 84rem there is no room to reserve, so it is hidden. */
@layer sections {

.s-toc { display: none; }

/* The rail floats over the page. It does not reserve a column: reserving one
   shifted the whole layout sideways and made the pages a different width from
   the rest of the site. Its own surface keeps it readable over whatever it
   happens to be sitting on. */
/* The rail overlays the page and never reflows it, so these pages stay the
   same width as the rest of the site. It rests as a slim strip of markers and
   opens to full labels on hover or keyboard focus, so it maps position at a
   glance without sitting on top of the prose. */
@media (min-width: 84rem) {
  .s-toc {
    display: block;
    position: fixed; top: 50%; left: var(--sp-3);
    transform: translateY(-50%);
    z-index: calc(var(--z-header) + 1);
    width: 2.5rem;
    padding: var(--sp-3);
    /* 80% transparent; the heavy blur is what holds the labels together */
    background: color-mix(in srgb, var(--g-paper) 20%, transparent);
    backdrop-filter: saturate(150%) blur(30px);
    border: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
    border-radius: var(--r-md);
    overflow: hidden;
    transition: width var(--dur-base) var(--ease),
                padding var(--dur-base) var(--ease),
                background var(--dur-base) var(--ease);
  }
  .s-toc:hover, .s-toc:focus-within {
    width: 13rem; padding: var(--sp-4);
    background: color-mix(in srgb, var(--g-paper) 72%, transparent);
  }
  .s-toc[hidden] { display: none; }

  /* labels occupy space only once the rail is open */
  .s-toc__title, .s-toc__label {
    opacity: 0; white-space: nowrap;
    transition: opacity var(--dur-fast) var(--ease);
  }
  .s-toc:hover .s-toc__title, .s-toc:hover .s-toc__label,
  .s-toc:focus-within .s-toc__title, .s-toc:focus-within .s-toc__label {
    opacity: 1; white-space: normal;
  }
}

.s-toc__title {
  margin-bottom: var(--sp-4);
  font-size: 10.5px; font-weight: var(--fw-semi);
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase;
  color: var(--t-body);
}

.s-toc__list { display: grid; gap: var(--sp-1); }

.s-toc__link {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) 0;
  text-decoration: none;
  /* Body weight rather than muted: at 60% transparency the panel sits on
     whatever is behind it, and muted grey disappeared over the dark footer. */
  color: var(--t-body);
  transition: color var(--dur-fast) var(--ease);
}
.s-toc__link:hover { color: var(--t-strong); }

/* The marker is a track; the fill inside is scaled by --toc-progress, which
   the script updates on scroll in both directions. */
.s-toc__marker {
  position: relative; display: block;
  width: 3px; height: 1.65rem; border-radius: 2px;
  background: var(--line);
  overflow: hidden; flex-shrink: 0;
}
.s-toc__fill {
  position: absolute; inset: 0;
  background: var(--toc-hue, var(--c-azure));
  transform: scaleY(var(--toc-progress, 0));
  transform-origin: top;
  transition: transform .12s linear;
}

.s-toc__label {
  min-width: 0;
  font-size: 12.5px; line-height: 1.3;
  overflow-wrap: anywhere;
}

.s-toc__item.is-current .s-toc__link { color: var(--t-strong); font-weight: var(--fw-semi); }
.s-toc__item.is-current .s-toc__marker { width: 4px; }

@media (prefers-reduced-motion: reduce) {
  .s-toc__fill { transition: none; }
}

}

/* ── under-construction.css ─────────────────────────── */
/* ── In preparation ───────────────────────────────────────────────────────
   For pages whose content is still being written. It states what is coming
   and offers a way forward, rather than being a dead end. */
@layer sections {

.s-uc__panel {
  max-width: 46rem;
  padding: var(--sp-7);
  background: var(--g-paper);
  border: 1px solid var(--line);
  border-left: 3px solid var(--a-amber);
  border-radius: var(--r-md);
}
.s-uc__tag {
  display: inline-block; margin-bottom: var(--sp-4);
  padding: 2px var(--sp-3); border-radius: var(--r-sm);
  background: var(--a-amber-tint); color: var(--a-amber-deep);
  font-size: 10.5px; font-weight: var(--fw-semi);
  letter-spacing: .08em; text-transform: uppercase;
}
.s-uc__title { margin-bottom: var(--sp-4); font-size: var(--fs-h3); }
.s-uc__lead  { color: var(--t-body); }
.s-uc__label {
  margin: var(--sp-6) 0 var(--sp-3);
  font-size: var(--fs-eyebrow); font-weight: var(--fw-semi);
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase;
  color: var(--t-muted);
}
.s-uc__list { display: grid; gap: var(--sp-2); }
.s-uc__list li {
  position: relative; padding-left: var(--sp-5);
  font-size: var(--fs-small); color: var(--t-body);
}
.s-uc__list li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 12px; height: 2px; border-radius: 2px; background: var(--c-azure);
}
.s-uc__actions { margin-top: var(--sp-6); }

}

/* ── print.css ─────────────────────────── */
/* ============================================================================
   PRINT — for printed pages and for the generated legal PDFs.
   The site was missing this entirely: printing any page produced the
   navigation, the contents rail and the whole footer alongside the content.
   ========================================================================= */

@layer utilities {
@media print {

  /* Chrome and Firefox drop background colours when printing. Anything that
     depends on a ground for contrast has to be re-stated in ink on white. */
  :root {
    --g-paper: var(--p-paper); --g-sand: var(--p-paper);
    --g-mist:  var(--p-paper); --g-ink:  var(--p-paper);
    --t-on-dark: var(--p-ink); --t-on-dark-body: var(--p-body);
    --t-on-dark-muted: var(--p-muted);
    --dg-surface: var(--p-paper); --dg-text: var(--p-ink);
    --dg-text-muted: var(--p-muted);
    --line-on-dark: var(--p-line);
  }

  body { background: var(--p-paper); color: var(--p-ink); font-size: 11pt; }

  /* Chrome, navigation and anything interactive have no meaning on paper */
  .c-header, .c-footer, .s-toc, .c-actions, .c-btn, .s-related,
  .s-partners, .skip { display: none !important; }

  .l-main { padding-left: 0 !important; }
  .l-section { padding-block: 0 0 1.2rem !important; }
  .l-section--ink * { color: var(--p-ink) !important; }

  /* A heading stranded at the foot of a page, or a paragraph split across
     one, is the usual failure when a web page is printed. */
  h1, h2, h3 { break-after: avoid-page; page-break-after: avoid; }
  p, li      { break-inside: avoid-page; orphans: 3; widows: 3; }

  /* A printed link is useless unless its target is written out. */
  a[href^="http"]::after,
  a[href^="mailto"]::after {
    content: " (" attr(href) ")";
    font-size: .85em; color: var(--p-muted); word-break: break-all;
  }
  a[href^="/"]::after { content: " (elyonx.com" attr(href) ")"; font-size: .85em; color: var(--p-muted); }

  /* Nothing animates on paper */
  *, *::before, *::after { animation: none !important; transition: none !important; }
  [data-reveal], [data-stagger] > * { opacity: 1 !important; transform: none !important; }

  @page { margin: 18mm; }
}
}
