/* quilyx.ai stage 2 preview. Dark-first, sixfold accent system, motion gated on html[data-motion="on"]. */

@font-face {
  font-family: "Raleway";
  src: url("../assets/fonts/raleway-vf.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../assets/fonts/ibm-plex-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

:root {
  --bg: #0C0C4C;
  --bg-deep: #080830;
  --ink: #FFFFFF;
  --ink-80: rgba(255, 255, 255, 0.84);
  --ink-60: rgba(255, 255, 255, 0.66);
  --ink-40: rgba(255, 255, 255, 0.42); /* decoration only (hairlines, underlines, borders): fails WCAG AA as text on this ground */
  --hair: rgba(255, 255, 255, 0.14);
  --geel: #FFCE00;
  --blauw: #3B7CFF;
  --groen: #10AD7C;
  --paars: #9336FF;
  --oranje: #FF6D24;
  --rood: #FF4040;
  --mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  --sans: "Raleway", system-ui, sans-serif;
  --wide: 68rem;
  --prose: 38rem; /* 26 Jul 2026 polish: was 44rem; brings body prose to the 60-75 cpl band */
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
html[data-motion="off"] { scroll-behavior: auto; }

body {
  background: var(--bg);
  background-image: radial-gradient(1200px 700px at 50% -10%, rgba(59, 124, 255, 0.10), transparent 70%);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-weight: 430;
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--geel); color: var(--bg); }
/* Focus ring adopts the section's carrying blade colour (--acc), falling back to geel
   outside an accent section, so keyboard focus travels through the same sixfold colour
   system as the section markers. Paired with the skewed blade tick appended below. */
:focus-visible { outline: 2px solid var(--acc, var(--geel)); outline-offset: 3px; border-radius: 2px; }

.skip {
  position: absolute; left: -999px; top: 0; z-index: 99;
  background: var(--geel); color: var(--bg); padding: 0.6rem 1rem; font-weight: 700;
}
.skip:focus { left: 0.5rem; top: 0.5rem; }

a { color: var(--ink); text-decoration-color: var(--ink-40); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--acc, var(--geel)); }

/* ---------- header ---------- */
/* Clear space rule: padding around the logo img is at least 50% of the rendered beeldmerk height. */
.top {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.8rem clamp(1rem, 4vw, 2.2rem);
}
html[data-motion="on"] .top { transition: background-color 0.3s ease, border-color 0.3s ease; }
.top { background: transparent; border-bottom: 1px solid transparent; }
.top.scrolled { background: rgba(9, 9, 52, 0.78); backdrop-filter: blur(10px); border-bottom-color: var(--hair); }
.brand img { display: block; height: 1.35rem; width: auto; }
.top-nav { display: flex; gap: 1.4rem; }
.top-nav a {
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-60); text-decoration: none;
}
.top-nav a:hover { color: var(--ink); }
/* language selector: English is primary, Dutch is the second version at /nl/ */
.top-right { display: flex; align-items: center; gap: clamp(1rem, 3vw, 2rem); }
.lang { display: flex; gap: 0.5rem; }
.lang a {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.12em;
  color: var(--ink-60); text-decoration: none;
  border: 1px solid var(--hair); border-radius: 999px; padding: 0.22rem 0.5rem;
}
.lang a:hover { color: var(--ink); border-color: var(--ink-40); }
/* The current language carries a filled chip, not just a brighter hairline. Below 640px the
   text label is hidden, so a 1px luminance shift would be the only cue left, and that is
   not enough on its own. aria-current carries the same state to assistive tech. */
.lang .lang-on { color: var(--ink); border-color: var(--ink-40); background: rgba(255, 255, 255, 0.13); }
.lang .flag { width: 15px; height: 10px; border-radius: 1.5px; display: block; flex: none; }

/* ---------- hero ---------- */
#hero {
  min-height: min(88vh, 720px); /* clamped so tall or portrait viewports do not balloon the hero into empty space */
  display: grid; place-content: center; justify-items: center;
  text-align: center;
  padding: 2rem clamp(1rem, 4vw, 2rem) 3rem;
}
/* The stage hugs the rendered mark instead of a tall invisible centering box (folded in
   from the v4 critique fix, 10 July 2026): better phone proportions, and the block
   padding keeps room for signature effects that reach slightly past the mark. */
.sig-stage { position: relative; width: min(56rem, 94vw); height: auto; padding: clamp(2.2rem, 5vh, 3.2rem) 0; display: grid; place-items: center; }
#sig { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
html[data-motion="on"] #sig { transition: opacity 0.45s ease; }
#sig.done { opacity: 0; }
.sig-mark { position: relative; z-index: 1; width: min(37rem, 82vw); }
.sig-mark svg { display: block; width: 100%; height: auto; }
html[data-motion="on"] .sig-mark svg { transition: opacity 0.55s ease; }
html[data-sig="resolved"] .sig-mark svg { opacity: 1; }
/* Failsafe reveal: the brand mark must never depend on signature.js resolving. The head
   anti-flash style hides .sig-mark svg until the engine sets data-sig; if the engine never
   runs (script blocked, 404s at deploy, or throws), this animation reveals the true mark on
   its own. During a normal run the engine sets opacity 1 within tens of ms, long before this
   fires at 1.8s, so it is invisible then; no-JS is already covered by the noscript rule. */
.sig-mark svg { animation: sig-failsafe-reveal 0.01s linear 1.8s forwards; }
@keyframes sig-failsafe-reveal { to { opacity: 1; } }

#replay {
  margin-top: 0.6rem;
  background: none; border: 1px solid var(--hair); color: var(--ink-60);
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase;
  padding: 0.45rem 0.9rem; border-radius: 999px; cursor: pointer;
  opacity: 0; visibility: hidden;
}
html[data-motion="on"] #replay { transition: opacity 0.4s ease 0.3s, visibility 0s 0.7s; }
html[data-sig="resolved"] #replay { opacity: 1; visibility: visible; }
#replay:hover { color: var(--ink); border-color: var(--ink-40); }

#hero h1 {
  margin-top: 1.6rem;
  font-size: clamp(2.05rem, 5.4vw, 3.55rem);
  font-weight: 770; letter-spacing: -0.015em; line-height: 1.08;
  max-width: 20ch;
  /* Dutch closes its compounds, so the NL headline carries a 19-letter word
     ("Programmamanagement") that is wider than a 375px viewport at the clamped size.
     hyphens:auto picks the right dictionary from <html lang>; break-word is the floor
     for any language whose dictionary is missing. Harmless in English, where no word
     in this headline is long enough to trigger either. */
  hyphens: auto;
  overflow-wrap: break-word;
}
@media (max-width: 420px) {
  /* one step smaller on small phones so the hyphenated Dutch compound still sets on two lines */
  #hero h1 { font-size: 1.85rem; }
}
#hero .lede {
  margin-top: 1.1rem; max-width: 44ch;
  color: var(--ink-60); font-size: clamp(1.05rem, 2vw, 1.2rem); font-weight: 450;
}
.chip {
  display: inline-flex; align-items: center; gap: 0.6rem;
  margin-top: 1.5rem; padding: 0.5rem 1rem;
  border: 1px solid var(--hair); border-radius: 999px;
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-60);
}
.chip::before { content: ""; flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--groen); }
.chip .chip-t { text-align: center; }
.nb { white-space: nowrap; }
.cue { display: inline-block; margin-top: 2.4rem; font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-60); text-decoration: none; }
.cue:hover { color: var(--ink); }

/* ---------- sections and sixfold accents ---------- */
main section { padding: clamp(3.6rem, 9vw, 6.5rem) clamp(1rem, 4vw, 2.2rem); }
.inner { max-width: var(--wide); margin: 0 auto; }
.prose { max-width: var(--prose); }
.prose p + p { margin-top: 1rem; }
.prose .lead { font-size: 1.15rem; color: var(--ink-80); }

/* Sovereignty statement, carried near the top of the claim section. Left blade rule in
   the section accent; keywords emphasised for scanning. */
/* Moved below the claim prose, 24 July 2026: the H1 promises programme delivery, so
   opening the section with a sentence about matching read as a non sequitur. The claim
   states itself first, the sovereignty position follows it. */
.sovereign {
  max-width: var(--prose); margin-top: 2.2rem;
  border-left: 3px solid var(--acc, var(--geel)); padding-left: 1.15rem;
  color: var(--ink-80); font-size: 1.08rem; line-height: 1.5;
}
p { color: var(--ink-80); }

.accent-geel   { --acc: var(--geel); }
.accent-blauw  { --acc: var(--blauw); }
.accent-groen  { --acc: var(--groen); }
.accent-paars  { --acc: var(--paars); }
.accent-oranje { --acc: var(--oranje); }
.accent-rood   { --acc: var(--rood); }

.sixline { position: relative; height: 1px; background: linear-gradient(90deg, transparent, var(--hair) 18%, var(--hair) 82%, transparent); max-width: var(--wide); margin: 0 auto; overflow: visible; }
.sixline i {
  position: absolute; left: 0; top: -1.5px; display: block;
  width: 84px; height: 4px; background: var(--acc, var(--geel));
  transform: skewX(-30deg);
}
html[data-motion="on"] .sixline i { opacity: 0; transform: skewX(-30deg) translateX(-70px); transition: opacity 0.6s ease, transform 0.7s cubic-bezier(0.22, 1, 0.36, 1); }
html[data-motion="on"] .inview .sixline i, html[data-motion="on"] section.inview .sixline i { opacity: 1; transform: skewX(-30deg) translateX(0); }

.kicker {
  display: flex; align-items: center; gap: 0.6rem;
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-60); margin-bottom: 1.1rem;
}
.kicker::before {
  content: ""; width: 15px; height: 11px; background: var(--acc, var(--geel));
  clip-path: polygon(28% 0, 100% 0, 72% 100%, 0 100%);
}
h2 { font-size: clamp(1.6rem, 3.4vw, 2.3rem); font-weight: 740; letter-spacing: -0.01em; line-height: 1.15; margin-bottom: 1.3rem; }
h3 { font-size: 1.35rem; font-weight: 700; }

/* reveal: only hides when motion is on (JS present); static and no-JS states show everything */
html[data-motion="on"] .reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.22, 1, 0.36, 1); }
html[data-motion="on"] .reveal.inview { opacity: 1; transform: none; }

/* ---------- systems ---------- */
.sys { border: 1px solid var(--hair); border-radius: 14px; padding: clamp(1.4rem, 3.5vw, 2.4rem); background: linear-gradient(180deg, rgba(255, 255, 255, 0.025), transparent 60%); position: relative; }
.sys + .sys { margin-top: 2rem; }
.sys-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.9rem 1.2rem; margin-bottom: 0.9rem; }
.badge {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase;
  border: 1px solid var(--acc); color: var(--ink-80);
  padding: 0.28rem 0.7rem; border-radius: 999px; white-space: nowrap;
}
.badge::before { content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--acc); margin-right: 0.45rem; vertical-align: 1px; }
.sys .what { max-width: var(--prose); color: var(--ink-80); }
.sys .why { max-width: var(--prose); color: var(--ink-60); margin-top: 0.6rem; }

.factrow { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.2rem; }
.factrow span {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.08em;
  color: var(--ink-60); border: 1px solid var(--hair); border-radius: 999px; padding: 0.3rem 0.75rem;
}
.hon { margin-top: 1.1rem; color: var(--ink-60); font-size: 0.95rem; max-width: var(--prose); }
.hon strong { color: var(--ink-80); font-weight: 600; }

/* Quilance flow (HTML diagram, reflows on mobile) */
.flow { list-style: none; display: flex; gap: 0; margin: 1.6rem 0 0.4rem; flex-wrap: nowrap; }
.flow li { display: flex; align-items: center; flex: 1; min-width: 0; }
.flow li::after {
  content: ""; flex: 1; height: 1px; margin: 0 0.4rem;
  background: linear-gradient(90deg, var(--acc), var(--hair));
  background-size: 200% 100%;
}
/* The connector pulse settles to the complete static reading after three passes
   instead of looping forever (folded in from the v2 critique fix, 10 July 2026). */
html[data-motion="on"] .inview .flow li::after { animation: flowpulse 2.6s linear 3; }
@keyframes flowpulse { from { background-position: 100% 0; } to { background-position: -100% 0; } }
.flow li:last-child::after { display: none; }
.stage {
  background: var(--bg-deep); color: var(--ink-80);
  border: 1px solid var(--hair); border-radius: 8px;
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase;
  padding: 0.55rem 0.7rem; cursor: default; white-space: nowrap;
}
.js-inspect .stage { cursor: pointer; }
.js-inspect .stage:hover { border-color: var(--acc); color: var(--ink); }
.stage[aria-pressed="true"] { border-color: var(--acc); color: var(--ink); box-shadow: 0 0 0 1px var(--acc) inset; }
.flow-notes { margin-top: 1rem; display: grid; gap: 0.5rem; }
.note { border-left: 2px solid var(--hair); padding: 0.15rem 0 0.15rem 0.9rem; color: var(--ink-60); font-size: 0.95rem; }
.note b { color: var(--ink-80); font-weight: 600; font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase; display: block; margin-bottom: 0.1rem; }
.js-inspect .note { display: none; }
.js-inspect .note.active { display: block; border-left-color: var(--acc); }

/* QuiDAS radial */
.quidas-grid { display: grid; grid-template-columns: minmax(0, 420px) 1fr; gap: clamp(1.2rem, 4vw, 2.6rem); align-items: center; margin-top: 1.4rem; }
#quidas-svg { width: 100%; height: auto; display: block; }
#quidas-svg .qd-grid line, #quidas-svg .qd-grid circle { stroke: rgba(255, 255, 255, 0.07); fill: none; }
#quidas-svg .qd-raw circle { fill: rgba(255, 255, 255, 0.12); }
#quidas-svg .qd-reg circle { fill: rgba(255, 255, 255, 0.45); }
#quidas-svg .qd-con circle { fill: var(--groen); }
#quidas-svg .qd-nop circle { fill: none; stroke: var(--oranje); stroke-width: 1.4; }
#quidas-svg .qd-hub { fill: var(--ink); }
#quidas-svg .qd-sweep { opacity: 0; transform-origin: 200px 200px; transform-box: view-box; }
html[data-motion="on"] .inview #quidas-svg .qd-sweep { opacity: 1; animation: qdsweep 3.2s cubic-bezier(0.3, 0, 0.2, 1) 0.3s 1 both; }
@keyframes qdsweep { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

.legend { display: grid; gap: 0.85rem; }
.legend div { display: grid; grid-template-columns: auto 1fr; gap: 0.7rem; align-items: baseline; }
.legend .n { font-family: var(--mono); font-size: 1.25rem; color: var(--ink); min-width: 4.2ch; text-align: right; }
.legend .t { color: var(--ink-60); font-size: 0.95rem; }
/* A legend row without a number spans the full width, flush left. */
.legend div.full { grid-template-columns: 1fr; }
.legend .t i { font-style: normal; display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 0.45rem; }
.legend .dot-reg { background: rgba(255, 255, 255, 0.45); }
.legend .dot-con { background: var(--groen); }
.legend .dot-nop { background: none; border: 1.5px solid var(--oranje); box-sizing: border-box; }
.legend .asof { font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-60); margin-top: 0.3rem; }

/* group headings: the two maturity groups inside section 3 (22 July 2026).
   Heading order is h2 section > h3 group > h4 system, so the card titles moved to h4. */
.grouphead { margin: 2.8rem 0 1.4rem; }
.grouphead h3 {
  font-family: var(--mono); font-size: 0.74rem; letter-spacing: 0.18em; text-transform: uppercase;
  font-weight: 400; color: var(--ink-80);
  display: flex; align-items: center; gap: 0.9rem;
}
.grouphead h3::after { content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, var(--acc), transparent 88%); }
.grouphead p { color: var(--ink-60); font-size: 0.95rem; max-width: var(--prose); margin-top: 0.55rem; }
.sys-head h4 { font-size: 1.35rem; font-weight: 700; }
.expansion {
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--acc); margin: -0.35rem 0 0.75rem;
}

/* Freelyx one-way sealed feed: same two-column figure-plus-legend shape as the QuiDAS
   radial, so the visualizations read as one family. The I.R.E.N.E. figure left this shape
   on 24 July 2026 when it became a full-width plate; it carries its labels inside the
   picture at desktop and falls back to the same legend underneath on narrow screens. */
.feed-grid {
  display: grid; grid-template-columns: minmax(0, 340px) 1fr;
  gap: clamp(1.2rem, 4vw, 2.6rem); align-items: center; margin-top: 1.4rem;
}
#freelyx-svg { width: 100%; height: auto; display: block; }

#freelyx-svg .fx-node rect { fill: rgba(255, 255, 255, 0.03); stroke: var(--hair); stroke-width: 1; }
#freelyx-svg .fx-portal rect { fill: rgba(255, 255, 255, 0.05); stroke: var(--acc); }
#freelyx-svg .fx-rec line { stroke: rgba(255, 255, 255, 0.28); stroke-width: 2; stroke-linecap: round; }
#freelyx-svg .fx-flow, #freelyx-svg .fx-arrow { fill: none; stroke: var(--acc); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
#freelyx-svg .fx-seal circle { fill: var(--bg-deep); stroke: var(--acc); stroke-width: 1.6; }
#freelyx-svg .fx-seal rect { fill: var(--acc); }
#freelyx-svg .fx-seal path { fill: none; stroke: var(--acc); stroke-width: 1.6; }
#freelyx-svg .fx-cred rect { fill: none; stroke: rgba(255, 255, 255, 0.3); stroke-width: 1; }
#freelyx-svg .fx-person circle, #freelyx-svg .fx-person path { fill: none; stroke: rgba(255, 255, 255, 0.45); stroke-width: 1.6; }
#freelyx-svg .fx-back { fill: none; stroke: rgba(255, 255, 255, 0.18); stroke-width: 1.4; stroke-dasharray: 5 5; }
#freelyx-svg .fx-cross path { stroke: var(--rood); stroke-width: 2.2; stroke-linecap: round; }
#freelyx-svg .fx-n { fill: var(--ink-60); font-family: var(--mono); font-size: 13px; text-anchor: end; }
/* one-shot draw of the two feed segments; settles to the complete static frame */
html[data-motion="on"] .inview #freelyx-svg .fx-flow { stroke-dasharray: 40; stroke-dashoffset: 40; animation: fxdraw 1s ease-out 0.25s both; }
@keyframes fxdraw { to { stroke-dashoffset: 0; } }

/* I.R.E.N.E.: rendered glass-brain plate with a coded light layer on top.
   Replaces the hand-drawn single-line brain, 24 July 2026, on the founder's pick of
   design/lab/irene-plate-demo.html. Split that carries the whole idea: the plate is the
   paint (brain, compartments, micro-scenes, printed routing), everything readable is code
   (numbers, labels, leader lines, padlock, every moving light). So type stays crisp and
   editable at any size, and the motion honours the site motion toggle instead of being
   baked into pixels. The plate is pure black, so mix-blend-mode screen drops the black
   out onto donkerblauw and no background match is needed.
   The sixth compartment is drawn closed on purpose. Showing a locked compartment argues
   the privacy claim; labelling its contents would break it. See ia.md 3e for the labels
   that were rejected and why. */
.ir-stage { position: relative; width: 100%; aspect-ratio: 1672 / 941; margin-top: 1.5rem; }
.ir-plate { position: absolute; inset: 0; width: 100%; height: 100%; display: block; mix-blend-mode: screen; }
.ir-layer { position: absolute; inset: 0; width: 100%; height: 100%; }

.ir-lead { fill: none; stroke: rgba(255, 255, 255, 0.42); stroke-width: 1.6; }
.ir-dot { fill: #7FE3FF; }
.ir-ring { fill: none; stroke: rgba(127, 227, 255, 0.55); stroke-width: 1.6; }
.ir-num { font-family: var(--mono); font-size: 25px; fill: #7FE3FF; letter-spacing: 0.06em; }
.ir-label { font-size: 27px; fill: #fff; font-weight: 600; }
.ir-sub { font-size: 22px; fill: rgba(255, 255, 255, 0.62); }
.ir-lock { fill: none; stroke: #9CEBFF; stroke-width: 3; }

/* Static routing under the pulses, so the paths still read with motion off. */
.ir-trace { fill: none; stroke: rgba(127, 227, 255, 0.18); stroke-width: 2; }

/* The light layer. A short dash runs the length of each path, so the glow reads as
   charge moving through the trace rather than the trace blinking. */
.ir-pulse {
  fill: none; stroke: #C6EFFF; stroke-width: 2.5; stroke-linecap: round;
  stroke-dasharray: 40 1000; stroke-dashoffset: 1040; opacity: 0;
}
/* Since the founder-picked motion clip (24 July 2026) the coded pulses carry the
   light only below 900px, where the clip is off; at desktop the clip is the light
   layer and the coded pulses stay quiet so the two never double. */
@media (max-width: 900px) {
  html[data-motion="on"] .sys.live .ir-pulse { opacity: 1; animation: irrun 3.4s linear infinite; }
  html[data-motion="on"] .sys.live .ir-core { animation: irbreathe 3.4s ease-in-out infinite; transform-origin: 830px 458px; }
}
/* Delays as classes, never inline style attributes: the two CSP style hashes are
   load-bearing and an inline style= would need unsafe-inline to render at all. */
.ir-p1  { animation-delay: 0s; }
.ir-p2  { animation-delay: 0.3s; }
.ir-p3  { animation-delay: 0.55s; }
.ir-p4  { animation-delay: 0.9s; }
.ir-p5  { animation-delay: 1.1s; }
.ir-p6  { animation-delay: 1.4s; }
.ir-p7  { animation-delay: 1.65s; }
.ir-p8  { animation-delay: 1.9s; }
.ir-p9  { animation-delay: 2.2s; }
.ir-p10 { animation-delay: 2.4s; }
.ir-p11 { animation-delay: 2.75s; }
.ir-p12 { animation-delay: 2.9s; }
@keyframes irrun { from { stroke-dashoffset: 1040; } to { stroke-dashoffset: 0; } }
@keyframes irbreathe {
  0%, 100% { transform: scale(1); opacity: 0.55; }
  50%      { transform: scale(1.22); opacity: 0.12; }
}

/* Narrow screens cannot carry type inside the plate: at 375 the stage is about 211px
   tall and the labels fall below a readable size. The in-plate text drops out and the
   same six lines return underneath as the HTML legend, which is the figure-plus-legend
   pattern the QuiDAS and Freelyx figures already use. */
.ir-legend { display: none; margin-top: 1.5rem; }
@media (max-width: 900px) {
  .ir-labels text, .ir-labels .ir-lead { display: none; }
  .ir-legend { display: grid; }
  /* The plate is composed wide, with generous empty margins that exist to hold the
     labels. Once the labels drop out those margins are dead space, and at 375 they
     would shrink the brain to about a third of the column. Crop to the brain instead:
     the stage goes near-square, the plate covers it from the centre, and the light layer
     crops identically because its preserveAspectRatio is "slice", which is the SVG
     equivalent of object-fit cover. So the pulses stay registered on the printed traces
     and the padlock stays on the sixth compartment. Only the outward routing is lost,
     and it lived in the margins that just went away. */
  .ir-stage { aspect-ratio: 5 / 6; overflow: hidden; }
  .ir-plate { object-fit: cover; object-position: center; }
}

.legend .dot-back { background: none; border: 1.5px dashed rgba(255, 255, 255, 0.35); box-sizing: border-box; }
.legend .t b { color: var(--ink-80); font-weight: 600; }
.feed-legend .n, .ir-legend .n, .ql-legend .n { color: var(--ink-60); font-size: 0.78rem; }
.ir-legend { gap: 0.65rem; }

/* The Quilance plate (24 July 2026): the intake-to-placement machine, same split as
   the I.R.E.N.E. plate. The render is the paint, everything readable is code, and the
   pure black plate composites onto donkerblauw with mix-blend-mode screen. The pulse
   layer runs the machine as a relay: in, split, triage, extract, dock, place. */
.ql-stage { position: relative; width: 100%; max-width: 780px; aspect-ratio: 1536 / 1024; margin: 1.5rem auto 0; }
.ql-plate { position: absolute; inset: 0; width: 100%; height: 100%; display: block; mix-blend-mode: screen; }
.ql-layer { position: absolute; inset: 0; width: 100%; height: 100%; }

.ql-lead { fill: none; stroke: rgba(255, 255, 255, 0.42); stroke-width: 1.6; }
.ql-dot { fill: #8FB4FF; }
.ql-num { font-family: var(--mono); font-size: 25px; fill: #8FB4FF; letter-spacing: 0.06em; }
.ql-label { font-size: 27px; fill: #fff; font-weight: 600; }
.ql-sub { font-size: 22px; fill: rgba(255, 255, 255, 0.62); }

/* Plate motion clips (24 July 2026): founder-picked Kling clips, self-hosted, muted
   loops, start and end frame pinned to the still plate so the loop is seamless.
   Shown with motion on while the card is on screen, AT EVERY WIDTH (founder ruling
   26 July 2026: the clips play on phones too, this is a showcase; the earlier
   below-900 hide is removed on his order). Reduced motion and no-JS keep the still
   plates. preload="none" keeps the clips out of the first view; site.js starts and
   stops playback on the same .live observer that gates every living figure. */
.ql-live, .ir-live, .fx-live {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: none;
  /* Same compositing as the stills: the clips render on pure black, screen drops
     the black onto donkerblauw. Without it the video paints a hard black box. */
  mix-blend-mode: screen;
}
html[data-motion="on"] .sys.live .ql-live,
html[data-motion="on"] .sys.live .ir-live,
html[data-motion="on"] .sys.live .fx-live { display: block; }
/* The Freelyx plate (24 July 2026): the sealed one-way conduit, same split as the
   other plates. The three stations carry live-text labels; the four legend lines
   below the plate are approved copy and stay visible at every width. The old coded
   #freelyx-svg figure is replaced; its fx-node/fx-seal/... rules below are records. */
.fx-stage { position: relative; width: 100%; max-width: 780px; aspect-ratio: 1672 / 941; margin: 1.5rem auto 1.25rem; }
.fx-plate { position: absolute; inset: 0; width: 100%; height: 100%; display: block; mix-blend-mode: screen; }
.fx-layer { position: absolute; inset: 0; width: 100%; height: 100%; }

.fx-lead { fill: none; stroke: rgba(255, 255, 255, 0.42); stroke-width: 1.6; }
.fx-dot { fill: #FFAD7A; }
.fx-num { font-family: var(--mono); font-size: 25px; fill: #FFAD7A; letter-spacing: 0.06em; }
.fx-label { font-size: 27px; fill: #fff; font-weight: 600; }
.fx-sub { font-size: 22px; fill: rgba(255, 255, 255, 0.62); }

@media (max-width: 900px) {
  .fx-labels text, .fx-labels .fx-lead { display: none; }
}

/* Below 900px the in-plate labels drop and the legend returns underneath. Unlike the
   brain there is no crop: the machine uses its full width, every station matters, so
   the stage keeps its own aspect ratio and simply scales down. */
.ql-legend { display: none; margin-top: 1.5rem; }
@media (max-width: 900px) {
  .ql-labels text, .ql-labels .ql-lead { display: none; }
  .ql-legend { display: grid; gap: 0.65rem; }
}

/* QEPMS prototype board */
#qepms { position: relative; }
.concept-mark {
  position: absolute; right: 1.2rem; top: 1rem;
  font-family: var(--mono); font-size: clamp(1.5rem, 4vw, 2.3rem); letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--paars); opacity: 0.16; transform: rotate(-8deg); pointer-events: none; user-select: none;
  max-width: 60%; text-align: right;
}
.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.7rem; margin-top: 1.5rem; }
.tile { border: 1px dashed rgba(147, 54, 255, 0.45); border-radius: 10px; background: rgba(147, 54, 255, 0.05); }
.tile summary {
  list-style: none; cursor: pointer; padding: 0.85rem 0.95rem;
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-80);
}
.tile summary::-webkit-details-marker { display: none; }
.tile summary:hover { color: var(--ink); }
.tile .bars { display: grid; gap: 4px; margin-top: 0.55rem; }
.tile .bars i { display: block; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, 0.16); }
.tile .bars i::before { content: ""; display: block; height: 100%; border-radius: 2px; background: var(--paars); width: 50%; opacity: 0.85; }
.tile .bars i.b30::before { width: 30%; }
.tile .bars i.b45::before { width: 45%; }
.tile .bars i.b60::before { width: 60%; }
.tile .bars i.b75::before { width: 75%; }
.tile .bars i.b90::before { width: 90%; }
.tile .drill { padding: 0 0.95rem 0.9rem; color: var(--ink-60); font-size: 0.88rem; border-top: 1px dashed rgba(147, 54, 255, 0.3); margin-top: 0.2rem; padding-top: 0.7rem; }
.tile[open] { border-style: solid; }
.board-note { margin-top: 0.9rem; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-60); }

/* ---------- approach ---------- */
.principles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.2rem; margin-top: 1.6rem; }
.principle { border-top: 2px solid var(--acc); padding-top: 0.9rem; }
.principle h3 { font-size: 1.05rem; margin-bottom: 0.35rem; }
.principle p { color: var(--ink-60); font-size: 0.95rem; }
.bridge { margin-top: 2rem; color: var(--ink-80); max-width: var(--prose); }

/* ---------- who ---------- */
.founders { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.4rem; max-width: 52rem; }
.card img { width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; border-radius: 10px; display: block; }
.card h3 { margin-top: 0.8rem; font-size: 1.1rem; }
.card p { color: var(--ink-60); font-size: 0.92rem; margin-top: 0.25rem; }
/* ---------- who: founder glass cockpit ----------
   The two founders (one shared cut-out photo, never altered) sit inside a glass-cockpit
   HUD. Each founder has a readout flanking the stage, wired back to them by a channel
   connector lead (Jeffry blauw / Channel 01 left, Bjorn oranje / Channel 02 right).
   The stage is laid out in percentages so the SVG viewBox connector leads stay aligned
   with the founders at every desktop width. Below 900px the HUD drops away and the
   readouts stack under the photo as channel-bordered cards.
   Channel colour is DECORATION ONLY (node, bracket, bio border): blauw/oranje as small
   text on this dark ground fail WCAG AA, so name/role/telemetry text stay white / ink-60.
   The two-card .founders/.card layout above is kept for the stage-2 variant record. */
.cockpit { max-width: var(--wide); margin: 0 auto; }
.cockpit-stage {
  position: relative; border-radius: 6px; overflow: hidden;
  background:
    linear-gradient(180deg, rgba(59,124,255,0.05), rgba(8,8,48,0) 46%, rgba(8,8,48,0.35)),
    radial-gradient(700px 420px at 50% 40%, rgba(59,124,255,0.06), transparent 70%);
  box-shadow: inset 0 0 0 1px var(--hair), inset 0 0 90px rgba(8,8,48,0.55);
}
.cockpit-hud { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
.cockpit-horizon {
  position: absolute; left: 0; right: 0; top: 52%; height: 2px; z-index: 1; pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(59,124,255,0.55), transparent);
  box-shadow: 0 0 22px rgba(59,124,255,0.35);
}
.cockpit-people {
  position: absolute; left: 50%; bottom: -4px; transform: translateX(-50%);
  width: 70%; height: auto; z-index: 2; pointer-events: none;
  filter: drop-shadow(0 26px 46px rgba(0,0,0,0.5));
}
.cockpit-readout { position: absolute; top: 118px; width: 23%; z-index: 3; font-family: var(--mono); }
/* --role is a brightened channel tint for the role line: the true blauw/oranje are borderline
   as small text on this ground, so the role text uses a lighter tint that clears WCAG AA while
   the node/bracket/bio-border keep the true brand --ch. */
.cockpit-left  { left: 0.75%; --ch: var(--blauw); --role: #66A0FF; }
.cockpit-right { right: 0.75%; text-align: right; --ch: var(--oranje); --role: #FF8A4D; }
.cockpit-tag {
  display: inline-flex; align-items: center; gap: 0.5rem; position: relative; padding: 0.34rem 0.62rem;
  font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink);
}
.cockpit-right .cockpit-tag { flex-direction: row-reverse; }
.cockpit-tag::before, .cockpit-tag::after { content: ""; position: absolute; width: 12px; height: 12px; }
.cockpit-left  .cockpit-tag::before { left: 0; top: 0; border-left: 2px solid var(--ch); border-top: 2px solid var(--ch); }
.cockpit-left  .cockpit-tag::after  { left: 0; bottom: 0; border-left: 2px solid var(--ch); border-bottom: 2px solid var(--ch); }
.cockpit-right .cockpit-tag::before { right: 0; top: 0; border-right: 2px solid var(--ch); border-top: 2px solid var(--ch); }
.cockpit-right .cockpit-tag::after  { right: 0; bottom: 0; border-right: 2px solid var(--ch); border-bottom: 2px solid var(--ch); }
.cockpit-node {
  width: 7px; height: 7px; flex: none; background: var(--ch);
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  box-shadow: 0 0 10px var(--ch);
}
.cockpit-role { margin-top: 0.5rem; font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--role); }
.cockpit-lines { margin-top: 0.85rem; display: flex; flex-direction: column; gap: 0.36rem; }
.cockpit-lines span {
  font-family: var(--sans); font-size: 0.86rem; line-height: 1.34; color: var(--ink-80);
  padding-left: 0.7rem; border-left: 1px solid var(--ch);
}
.cockpit-right .cockpit-lines span { padding-left: 0; padding-right: 0.7rem; border-left: none; border-right: 1px solid var(--ch); }
.cockpit-telemetry {
  display: flex; align-items: center; gap: 0.9rem; margin-top: 1rem;
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-60);
}
.cockpit-telemetry i { flex: 1; height: 1px; background: var(--hair); }

@media (min-width: 900px) {
  .cockpit-stage { height: 560px; }
}
@media (max-width: 899px) {
  .cockpit-hud, .cockpit-horizon { display: none; }
  .cockpit-stage { height: auto; padding: 0.4rem 0; background: none; box-shadow: none; overflow: visible; display: flex; flex-direction: column; gap: 1.6rem; }
  .cockpit-people { position: static; transform: none; width: min(340px, 76%); margin: 0 auto; }
  .cockpit-readout { position: static; width: auto; top: auto; border-left: 2px solid var(--ch); padding-left: 0.95rem; }
  .cockpit-right { text-align: left; }
  .cockpit-right .cockpit-tag { flex-direction: row; }
  .cockpit-right .cockpit-lines span { padding-left: 0.7rem; padding-right: 0; border-left: 1px solid var(--ch); border-right: none; }
  .cockpit-telemetry { flex-wrap: wrap; justify-content: center; gap: 0.5rem 1rem; }
  .cockpit-telemetry i { display: none; }
}
.programs { margin-top: 2.2rem; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.programs span { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.08em; color: var(--ink-80); border: 1px solid var(--hair); border-radius: 999px; padding: 0.4rem 0.9rem; }
.smallprint { margin-top: 0.6rem; font-size: 0.8rem; color: var(--ink-60); }

/* ---------- gtc + contact ----------
   Centred again 24 July 2026 on the founder's call, reversing the 12 July left-align.
   These are the two closing blocks and they are short: pinned left inside a 1080px wrap
   in a 1440px window, a 46ch paragraph left the whole right half of the section empty,
   which is what read as broken. The section blade on the sixline stays left, like every
   other section, so the page keeps its rhythm. */
#gtc .inner, #contact .inner { text-align: center; }
#gtc .kicker, #contact .kicker { justify-content: center; }
#gtc p, #contact p { max-width: 46ch; margin-left: auto; margin-right: auto; }
.mailto {
  display: inline-block; margin-top: 1.6rem;
  font-family: var(--mono); font-size: clamp(1rem, 2.6vw, 1.35rem);
  color: var(--bg); background: var(--geel); text-decoration: none;
  padding: 0.85rem 1.6rem; border-radius: 10px; font-weight: 400;
}
.mailto:hover { filter: brightness(1.07); }

/* ---------- footer ---------- */
footer { border-top: 1px solid var(--hair); padding: 2.2rem clamp(1rem, 4vw, 2.2rem) 2.8rem; }
.foot { max-width: var(--wide); margin: 0 auto; display: grid; gap: 1.4rem; }
.foot-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; }
.foot img { height: 1.2rem; width: auto; display: block; }
.foot-links { display: flex; flex-wrap: wrap; gap: 1.2rem; font-size: 0.85rem; }
.foot-links a { color: var(--ink-60); }
.foot-meta { display: flex; flex-wrap: wrap; gap: 0.8rem 1.6rem; align-items: center; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.08em; color: var(--ink-60); }
#motion-toggle {
  background: none; border: 1px solid var(--hair); color: var(--ink-60); cursor: pointer;
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 0.35rem 0.8rem; border-radius: 999px;
}
#motion-toggle:hover { color: var(--ink); border-color: var(--ink-40); }

/* ---------- colophon page ---------- */
.doc { max-width: var(--prose); margin: 0 auto; padding: 3rem clamp(1rem, 4vw, 2rem) 4rem; }
.doc h1 { font-size: clamp(1.8rem, 4vw, 2.6rem); font-weight: 760; margin-bottom: 1rem; }
.doc h2 { font-size: 1.15rem; margin: 2.2rem 0 0.7rem; }
.doc ul { list-style: none; }
.doc li { padding-left: 1.2rem; position: relative; color: var(--ink-80); margin: 0.35rem 0; }
.doc li::before { content: ""; position: absolute; left: 0; top: 0.6em; width: 11px; height: 8px; background: var(--geel); clip-path: polygon(28% 0, 100% 0, 72% 100%, 0 100%); }
.doc code, .doc .mono { font-family: var(--mono); font-size: 0.85em; color: var(--ink-80); }
.telemetry { border: 1px solid var(--hair); border-radius: 10px; padding: 1.1rem 1.3rem; margin-top: 1rem; font-family: var(--mono); font-size: 0.8rem; color: var(--ink-60); display: grid; gap: 0.4rem; }
.telemetry b { color: var(--ink); font-weight: 400; }

/* ---------- desktop gutter treatment ----------
   Folded in from the v3 critique fix, 10 July 2026. The three --prose blocks left a
   bare 384px right column at laptop widths. #claim pairs the intro with a pull-quote
   (aria-hidden: it repeats adjacent body copy); the bridge and firm lines extend a
   hairline into the gutter, echoing the sixline motif. Narrow viewports keep the
   single-column baseline layout. */
.pull {
  display: none;
  border-left: 4px solid var(--acc, var(--geel));
  padding-left: 1.2rem;
  font-weight: 740; font-size: clamp(1.3rem, 2.3vw, 1.7rem);
  line-height: 1.3; letter-spacing: -0.01em; color: var(--ink);
  max-width: 17ch;
}
@media (min-width: 900px) {
  .claim-cols {
    display: grid; grid-template-columns: minmax(0, var(--prose)) 1fr;
    gap: clamp(2.5rem, 6vw, 5rem); align-items: center;
  }
  .pull { display: block; }
  /* The desktop bridge hairline (a 1px gradient in a second grid column) was
     removed 24 July 2026 on Jeffry's instruction; the bridge is plain prose. */
}

/* ---------- responsive ---------- */
@media (max-width: 860px) {
  .principles, .tiles { grid-template-columns: 1fr 1fr; }
  .quidas-grid, .feed-grid { grid-template-columns: 1fr; }
  #quidas-svg { max-width: 380px; margin: 0 auto; }
  #freelyx-svg { max-width: 300px; margin: 0 auto; }
}
@media (max-width: 640px) {
  body { font-size: 1rem; }
  /* all three nav labels stay visible on phones; they are short mono caps, so they fit at a slightly smaller size */
  .top-nav { gap: 0.7rem; }
  .top-nav a { font-size: 0.66rem; letter-spacing: 0.1em; }
  /* phones: the flags carry the meaning, the labels come off so the header fits */
  .top-right { gap: 0.7rem; }
  /* vertical padding keeps the hit box at the WCAG 2.5.8 minimum once the label is hidden */
  .lang a { padding: 0.42rem 0.4rem; gap: 0; }
  .lang a span { display: none; }
}
/* Small phones: the Dutch nav labels are longer than the English ones, so the header
   needs the extra room. Logo clear space stays above the 50% beeldmerk-height rule. */
@media (max-width: 420px) {
  .top { padding-left: 0.8rem; padding-right: 0.8rem; }
  .brand img { height: 1.05rem; }
  .top-nav { gap: 0.5rem; }
  .top-nav a { font-size: 0.62rem; letter-spacing: 0.06em; }
  .flow { flex-direction: column; align-items: stretch; gap: 0; }
  .flow li { flex-direction: column; align-items: stretch; }
  .flow .stage { text-align: center; }
  .flow li::after { width: 1px; height: 14px; margin: 4px auto; flex: none; background: linear-gradient(180deg, var(--acc), var(--hair)); }
  html[data-motion="on"] .inview .flow li::after { animation: none; }
  .principles, .tiles, .founders { grid-template-columns: 1fr; }
  .concept-mark { font-size: 1.6rem; right: 0.8rem; }
}

/* ---------- hero signature: Six Stamps reveal states ----------
   Consolidated from the picked v3 variant on 11 July 2026 (stage 3). During the beat
   sequence the lockup SVG itself is visible and its parts are gated in; the resolved,
   static and no-JS states render the untouched baseline mark (same geometry, fills and
   stacking), so the resolved hero composites byte-identically to the original lockup.
   Every rule below is scoped to html[data-sig="stamping"], the phase the signature
   engine sets while the beat sequence runs. */
html[data-sig="stamping"] .sig-mark svg { opacity: 1; }
/* The wordmark hides at once when a run begins, with no fade: on a replay it comes from
   fully visible, and a fade there showed the word for a moment before the first stamp
   (founder report, 2 October 2026). The fade lives on .in only. */
html[data-sig="stamping"] #mark-word { opacity: 0; transition: none; }
/* Dotted-to-solid morph: the engine adds .in to the wordmark group while the last
   particles are still arriving, so the true vector letters fade in under the thinning
   particle layer and the hand-off has no pop. */
html[data-sig="stamping"] #mark-word.in { opacity: 1; transition: opacity 0.5s ease; }
/* Skip path: when the sequence is skipped straight to resolved, the wordmark still
   eases in rather than popping. */
html[data-motion="on"][data-sig="resolved"] #mark-word { transition: opacity 0.4s ease; }
/* A stamp waits invisible, slightly enlarged around the beeldmerk center (11.2% 50%
   of the lockup viewBox). Per-path classes, not wrapper groups: the twelve blade paths
   keep the brand file's exact document order, so the resolved compositing is
   byte-identical to the original mark; the two paths of a color stamp together. */
html[data-sig="stamping"] #mark-blades .stamp-p {
  opacity: 0;
  transform: scale(1.04);
  transform-box: view-box;
  transform-origin: 11.2% 50%;
}
/* The beat lands: a fast opacity hit with a tiny scale settle. */
html[data-sig="stamping"] #mark-blades .stamp-p.on {
  opacity: 1;
  transform: scale(1);
  transition: opacity 0.14s ease-out, transform 0.15s cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---------- section blade stamp-in (the second act, in budget) ----------
   The Six Stamps percussion echoes down the page: each section kicker carries its
   section's blade colour, and as the section enters view its chevron stamps in like a
   hero beat, in blade order (geel, blauw, oranje, rood, groen, geel). CSS-only, driven
   by the IntersectionObserver .inview class the reveal system already sets, so it costs
   nothing after entry, spins up no rAF loop, and shows the complete static chevron under
   reduced motion or no-JS. This replaces the direction-2 continuous particle bloodstream,
   which belonged to the Crystallize concept, not the picked Six Stamps signature. */
html[data-motion="on"] .kicker::before {
  opacity: 0;
  transform: translateX(-10px) scaleX(0.5) skewX(-10deg);
  transform-origin: left center;
}
html[data-motion="on"] .inview .kicker::before {
  opacity: 1;
  transform: none;
  transition: opacity 0.16s ease-out 0.14s, transform 0.34s cubic-bezier(0.22, 1, 0.36, 1) 0.14s;
}

/* ---------- focus tick on the blade geometry (micro-moment 5) ----------
   A skewed accent mark, sibling to the accent-coloured :focus-visible outline, echoing
   the sixline bar and kicker chevron. Drawn outside the control's box (the control is
   only made position:relative, with no offset, so nothing shifts) and only on standalone
   interactive text controls, so it never disturbs prose or the AA-visible outline. */
.cue, #replay, .mailto, .top-nav a, .foot-links a { position: relative; }
.cue:focus-visible::after,
#replay:focus-visible::after,
.mailto:focus-visible::after,
.top-nav a:focus-visible::after,
.foot-links a:focus-visible::after {
  content: ""; position: absolute; left: -0.72rem; top: 50%; margin-top: -2px;
  width: 11px; height: 4px; background: var(--acc, var(--geel));
  transform: skewX(-30deg); pointer-events: none;
}

/* ---------- NVIDIA Inception member badge (programs block) ----------
   The supplied full-colour badge carries its own white plate, so it reads as a white
   chip on donkerblauw. Shown unaltered (colours, proportions and text untouched) per the
   member guidelines; sized well below the hero Quilyx mark and given clear space. Exact
   minimum size and clear-space against the Member Badge PDF are a stage-3 gate check. */
/* NVIDIA Inception badge: unaltered full-colour file, height:auto-scaled so proportions are
   never changed. 56px tall is well above the 30px digital minimum and stays smaller than the
   Quilyx mark. margin gives ~half-badge-height clear space (the SVG also carries its own
   transparent padding), per the "Member Badge" guideline (brand-assets/NVIDIA). */
.nv-badge { display: block; height: 56px; width: auto; margin: 1.8rem 0 1.1rem; }
/* Footer trademark attribution, required whenever NVIDIA is mentioned. */
.legal-attr { margin-top: 1.4rem; font-size: 0.72rem; line-height: 1.5; color: var(--ink-60); max-width: 60ch; }

/* ---------- 404 page: the radar-blade micro-moment ----------
   One mark blade sweeps a sixfold radar field, resolving to a static parked blade under
   reduced motion. Gated purely on the media query so the page needs no JavaScript at all.
   Compositor-only transform; browsers pause it while the tab is hidden. */
.notfound { max-width: 40rem; margin: 0 auto; padding: clamp(3rem, 8vw, 5rem) clamp(1rem, 4vw, 2rem) 5rem; text-align: center; display: grid; justify-items: center; }
.radar { width: min(240px, 60vw); margin-bottom: 1.8rem; }
.radar svg { width: 100%; height: auto; display: block; }
.nf-grid circle, .nf-grid line { stroke: rgba(255, 255, 255, 0.08); fill: none; }
.nf-blade { fill: var(--oranje); }
.nf-hub { fill: var(--ink); }
.radar-sweep { transform-box: view-box; transform-origin: 120px 120px; }
@media (prefers-reduced-motion: no-preference) {
  .radar-sweep { animation: nfradar 4.8s linear infinite; }
}
@keyframes nfradar { to { transform: rotate(360deg); } }
.nf-code { font-family: var(--mono); font-size: 0.9rem; letter-spacing: 0.32em; color: var(--oranje); }
.notfound h1 { font-size: clamp(1.8rem, 5vw, 2.8rem); font-weight: 760; margin: 0.6rem 0 1rem; max-width: 18ch; }
.nf-msg { color: var(--ink-60); max-width: 42ch; }
.notfound .cue { margin-top: 2rem; }

/* ================= living figures (24 July 2026) =================
   The five system figures animate only while their card is on screen and
   motion is on. Gating: html[data-motion="on"] plus .live, a class that
   js/site.js toggles with an IntersectionObserver while the article
   intersects the viewport. Off-screen, reduced motion and no-JS all render
   the complete static figures. All motion is CSS; the only JS involvement
   is the QuiDAS per-dot delay computation, CSSOM properties only. */

/* ---- QuiDAS: the living radar. Continuous sweep replaces the one-shot
   entrance while the card is live; every dot blips at the moment the wedge
   crosses its real angle (delays computed from geometry in site.js). ---- */
html[data-motion="on"] .sys.live #quidas-svg .qd-sweep { opacity: 1; animation: qdrot 16s linear infinite; }
@keyframes qdrot { to { transform: rotate(360deg); } }
html[data-motion="on"] .sys.live #quidas-svg .qd-raw circle { animation: qdblipraw 16s linear infinite; }
html[data-motion="on"] .sys.live #quidas-svg .qd-reg circle { animation: qdblipreg 16s linear infinite; }
html[data-motion="on"] .sys.live #quidas-svg .qd-con circle { animation: qdblipcon 16s linear infinite; }
html[data-motion="on"] .sys.live #quidas-svg .qd-nop circle { animation: qdping 16s linear infinite; }
html[data-motion="on"] .sys.live #quidas-svg .qd-hub { animation: qdhub 4s ease-in-out infinite; }
@keyframes qdblipraw { 0%, 100% { fill: rgba(255,255,255,0.12); } 1.2% { fill: rgba(255,255,255,0.42); } 9% { fill: rgba(255,255,255,0.12); } }
@keyframes qdblipreg { 0%, 100% { fill: rgba(255,255,255,0.45); } 1.2% { fill: rgba(255,255,255,0.95); } 10% { fill: rgba(255,255,255,0.45); } }
@keyframes qdblipcon { 0%, 100% { fill: var(--groen); r: 3.1px; } 1.2% { fill: #7ee6c4; r: 4.2px; } 12% { fill: var(--groen); r: 3.1px; } }
@keyframes qdping { 0%, 100% { stroke: var(--oranje); stroke-opacity: 1; r: 4.2px; stroke-width: 1.4px; } 1.2% { stroke: #ffb184; r: 4.6px; stroke-width: 1.6px; } 7% { stroke-opacity: 0.55; r: 7.5px; stroke-width: 0.8px; } 14% { stroke: var(--oranje); stroke-opacity: 1; r: 4.2px; stroke-width: 1.4px; } }
@keyframes qdhub { 0%, 100% { opacity: 1; } 50% { opacity: 0.78; } }

/* ---- Quilance: the living flow. One request, one bullet, travels the
   line each cycle; every chip stamps as it arrives (founder simplification
   24 July 2026: same bullet the whole way, no transformations). The .lane
   spans replace the li::after connectors so the bullet has a track. ---- */
/* DEAD RULES, record only (26 Jul 2026 polish): the coded #quilance-flow figure was
   replaced by the painted plate plus clip on 24 July 2026; its markup no longer exists
   in either twin. Kept as the decision record, like the fx-* rules above. */
#quilance-flow .flow li::after { display: none; }
.flow .lane { flex: 1; position: relative; height: 1px; margin: 0 6px; min-width: 14px; background: linear-gradient(90deg, var(--acc), var(--hair)); }
.flow .pkt { position: absolute; top: 50%; left: 0; transform: translate(-50%, -50%); width: 7px; height: 7px; border-radius: 50%; background: #6FA1FF; box-shadow: 0 0 6px rgba(111, 161, 255, 0.55); opacity: 0; }
html[data-motion="on"] .sys.live .lane1 .pkt { animation: qllane1 12s linear infinite; }
html[data-motion="on"] .sys.live .lane2 .pkt { animation: qllane2 12s linear infinite; }
html[data-motion="on"] .sys.live .lane3 .pkt { animation: qllane3 12s linear infinite; }
html[data-motion="on"] .sys.live .lane4 .pkt { animation: qllane4 12s linear infinite; }
html[data-motion="on"] .sys.live .lane5 .pkt { animation: qllane5 12s linear infinite; }
@keyframes qllane1 { 0%, 2.9% { left: 0; opacity: 0; } 3.5% { opacity: 1; } 9.8% { opacity: 1; } 10.4% { left: 100%; opacity: 0; } 100% { left: 100%; opacity: 0; } }
@keyframes qllane2 { 0%, 13.3% { left: 0; opacity: 0; } 13.9% { opacity: 1; } 20.2% { opacity: 1; } 20.8% { left: 100%; opacity: 0; } 100% { left: 100%; opacity: 0; } }
@keyframes qllane3 { 0%, 23.8% { left: 0; opacity: 0; } 24.4% { opacity: 1; } 30.7% { opacity: 1; } 31.3% { left: 100%; opacity: 0; } 100% { left: 100%; opacity: 0; } }
@keyframes qllane4 { 0%, 34.2% { left: 0; opacity: 0; } 34.8% { opacity: 1; } 41.1% { opacity: 1; } 41.7% { left: 100%; opacity: 0; } 100% { left: 100%; opacity: 0; } }
@keyframes qllane5 { 0%, 44.6% { left: 0; opacity: 0; } 45.2% { opacity: 1; } 51.5% { opacity: 1; } 52.1% { left: 100%; opacity: 0; } 100% { left: 100%; opacity: 0; } }
html[data-motion="on"] .sys.live .flow li:nth-child(1) .stage:not([aria-pressed="true"]) { animation: qlstamp0 12s linear infinite; }
html[data-motion="on"] .sys.live .flow li:nth-child(2) .stage:not([aria-pressed="true"]) { animation: qlstamp1 12s linear infinite; }
html[data-motion="on"] .sys.live .flow li:nth-child(3) .stage:not([aria-pressed="true"]) { animation: qlstamp2 12s linear infinite; }
html[data-motion="on"] .sys.live .flow li:nth-child(4) .stage:not([aria-pressed="true"]) { animation: qlstamp3 12s linear infinite; }
html[data-motion="on"] .sys.live .flow li:nth-child(5) .stage:not([aria-pressed="true"]) { animation: qlstamp4 12s linear infinite; }
html[data-motion="on"] .sys.live .flow li:nth-child(6) .stage:not([aria-pressed="true"]) { animation: qlstamp5 12s linear infinite; }
@keyframes qlstamp0 { 0% { border-color: var(--hair); color: var(--ink-60); } 1% { border-color: var(--acc); color: var(--ink); } 4.6%, 100% { border-color: var(--hair); color: var(--ink-60); } }
@keyframes qlstamp1 { 0%, 10.4% { border-color: var(--hair); color: var(--ink-60); } 11.4% { border-color: var(--acc); color: var(--ink); } 15%, 100% { border-color: var(--hair); color: var(--ink-60); } }
@keyframes qlstamp2 { 0%, 20.8% { border-color: var(--hair); color: var(--ink-60); } 21.8% { border-color: var(--acc); color: var(--ink); } 25.4%, 100% { border-color: var(--hair); color: var(--ink-60); } }
@keyframes qlstamp3 { 0%, 31.3% { border-color: var(--hair); color: var(--ink-60); } 32.3% { border-color: var(--acc); color: var(--ink); } 35.9%, 100% { border-color: var(--hair); color: var(--ink-60); } }
@keyframes qlstamp4 { 0%, 41.7% { border-color: var(--hair); color: var(--ink-60); } 42.7% { border-color: var(--acc); color: var(--ink); } 46.3%, 100% { border-color: var(--hair); color: var(--ink-60); } }
@keyframes qlstamp5 { 0%, 52.1% { border-color: var(--hair); color: var(--ink-60); } 53.1% { border-color: var(--acc); color: var(--ink); } 57.5%, 100% { border-color: var(--hair); color: var(--ink-60); } }

/* ---- Freelyx: the airlock. One assignment drops, the shackle lifts just
   long enough, the portal receives, the professional reads, and the crossed
   return path answers once: no way back. Line-drawn, no glow. ---- */
#freelyx-svg .fx-pkt { fill: #FFB184; opacity: 0; }
#freelyx-svg .fx-seal path { transform-box: fill-box; transform-origin: center; }
html[data-motion="on"] .sys.live #freelyx-svg .fx-pkt { animation: fxdrop 10s linear infinite; }
@keyframes fxdrop { 0%, 3% { transform: translateY(0); opacity: 0; } 5% { opacity: 1; } 14% { transform: translateY(35px); } 20% { transform: translateY(52px); } 26% { transform: translateY(70px); } 36% { transform: translateY(112px); opacity: 1; } 40% { transform: translateY(122px); opacity: 0; } 48% { transform: translateY(170px); opacity: 0; } 50% { transform: translateY(176px); opacity: 1; } 56% { transform: translateY(196px); opacity: 1; } 60% { transform: translateY(202px); opacity: 0; } 100% { transform: translateY(202px); opacity: 0; } }
html[data-motion="on"] .sys.live #freelyx-svg .fx-seal path { animation: fxshackle 10s linear infinite; }
@keyframes fxshackle { 0%, 13% { transform: translateY(0); } 16% { transform: translateY(-3px); } 24% { transform: translateY(-3px); } 27%, 100% { transform: translateY(0); } }
html[data-motion="on"] .sys.live #freelyx-svg .fx-seal circle { animation: fxsealring 10s linear infinite; }
@keyframes fxsealring { 0%, 13% { stroke: var(--acc); } 18% { stroke: #FFB184; } 27%, 100% { stroke: var(--acc); } }
html[data-motion="on"] .sys.live #freelyx-svg .fx-cred rect:first-child { animation: fxpill 10s linear infinite; }
@keyframes fxpill { 0%, 38% { stroke: rgba(255,255,255,0.3); } 41% { stroke: #FFB184; } 46%, 100% { stroke: rgba(255,255,255,0.3); } }
html[data-motion="on"] .sys.live #freelyx-svg .fx-person circle { animation: fxread 10s linear infinite; }
@keyframes fxread { 0%, 56% { stroke: rgba(255,255,255,0.45); } 59% { stroke: #fff; } 64%, 100% { stroke: rgba(255,255,255,0.45); } }
html[data-motion="on"] .sys.live #freelyx-svg .fx-cross path { animation: fxnoback 10s linear infinite; }
@keyframes fxnoback { 0%, 68% { stroke-width: 2.2; } 71% { stroke-width: 3.2; } 74%, 100% { stroke-width: 2.2; } }

/* ---- QEPMS: the Horizon miniature, hand-built from QEPMS/demo-v1's own
   design language and synthetic data. Four pre-built level boards; the
   ladder dives portfolio, programme, project, work package and rises back,
   on the demo's step ease. Motion off shows the portfolio only. ---- */
.qe-board { position: relative; margin-top: 1.5rem; height: 240px; border: 1px solid var(--hair); border-radius: 10px; overflow: hidden; background: rgba(255,255,255,0.02); }
.qe-level { position: absolute; inset: 0; }
.qe-l1, .qe-l2, .qe-l3 { opacity: 0; }
.qe-cap { position: absolute; top: 8px; left: 10px; font-family: var(--mono); font-size: 8.5px; letter-spacing: 0.1em; text-transform: uppercase; color: #A9B0DC; z-index: 2; }
.qe-grid { position: absolute; top: 0; bottom: 0; width: 1px; background: rgba(255,255,255,0.055); }
.qe-grid.year { background: rgba(255,255,255,0.14); }
.qg1 { left: 2%; } .qg2 { left: 10.3%; } .qg3 { left: 18.6%; } .qg4 { left: 26.9%; } .qg5 { left: 35.2%; } .qg6 { left: 43.5%; } .qg7 { left: 51.8%; } .qg8 { left: 60.1%; } .qg9 { left: 68.4%; } .qg10 { left: 76.7%; } .qg11 { left: 85%; } .qg12 { left: 93.3%; }
.qh1 { left: 14%; } .qh2 { left: 31%; } .qh3 { left: 48%; } .qh4 { left: 65%; } .qh5 { left: 82%; }
.qe-yr { position: absolute; bottom: 6px; font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em; color: #A9B0DC; transform: translateX(-50%); }
.qy1 { left: 4%; } .qy2 { left: 35.2%; } .qy3 { left: 68.4%; }
.qe-today { position: absolute; top: 8px; bottom: 22px; left: 52%; width: 1px; background: rgba(255,206,0,0.55); }
.qe-today-cap { position: absolute; top: 14px; left: 52%; transform: translateX(-50%); font-family: var(--mono); font-size: 8.5px; letter-spacing: 0.08em; color: rgba(255,206,0,0.8); }
.qe-bar { position: absolute; height: 26px; display: flex; align-items: center; gap: 6px; padding: 0 8px; border: 1px solid rgba(255,255,255,0.4); border-radius: 9px; background: #12125A; white-space: nowrap; overflow: hidden; }
.qe-bar .lbl { font-size: 11.5px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; flex: 1 1 auto; min-width: 20px; }
.qe-bar .mth { font-family: var(--mono); font-size: 8.5px; letter-spacing: 0.06em; color: #A9B0DC; margin-left: auto; flex: none; }
.qe-bar .mth.none { border: 1px dashed #A9B0DC; border-radius: 4px; padding: 0 4px; }
.qe-bar.slim { height: 20px; border-radius: 7px; }
.qe-bar.slim .lbl { font-size: 10.5px; font-weight: 400; }
.qe-chip { flex: none; display: inline-flex; align-items: center; gap: 3px; border: 1px solid rgba(255,255,255,0.4); border-radius: 999px; padding: 1px 5px; min-height: 12px; }
.qe-chip .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--geel); }
.qe-l0 .qb1 { left: 4%; width: 42%; top: 20px; } .qe-l0 .qb2 { left: 18%; width: 52%; top: 58px; } .qe-l0 .qb3 { left: 30%; width: 48%; top: 96px; } .qe-l0 .qb4 { left: 44%; width: 48%; top: 134px; } .qe-l0 .qb5 { left: 10%; width: 28%; top: 172px; }
.qe-l1 .qb1 { left: 6%; width: 40%; top: 36px; } .qe-l1 .qb2 { left: 34%; width: 40%; top: 92px; } .qe-l1 .qb3 { left: 48%; width: 40%; top: 140px; } .qe-l1 .qb4 { left: 60%; width: 34%; top: 184px; }
.qe-l2 .qb1 { left: 8%; width: 32%; top: 36px; } .qe-l2 .qb2 { left: 22%; width: 40%; top: 80px; } .qe-l2 .qb3 { left: 36%; width: 36%; top: 124px; } .qe-l2 .qb4 { left: 62%; width: 30%; top: 168px; }
.qe-l3 .qb1 { left: 28%; width: 24%; top: 42px; } .qe-l3 .qb2 { left: 38%; width: 28%; top: 86px; } .qe-l3 .qb3 { left: 44%; width: 26%; top: 130px; } .qe-l3 .qb4 { left: 56%; width: 22%; top: 174px; }
.qe-l0 { transform-origin: 54% 45%; }
.qe-l1 { transform-origin: 54% 44%; }
.qe-l2 { transform-origin: 54% 50%; }
.qe-l3 { transform-origin: 50% 50%; }
html[data-motion="on"] .sys.live .qe-l0 { animation: qeL0 24s cubic-bezier(0.22, 0.9, 0.3, 1) infinite; }
html[data-motion="on"] .sys.live .qe-l1 { animation: qeL1 24s cubic-bezier(0.22, 0.9, 0.3, 1) infinite; }
html[data-motion="on"] .sys.live .qe-l2 { animation: qeL2 24s cubic-bezier(0.22, 0.9, 0.3, 1) infinite; }
html[data-motion="on"] .sys.live .qe-l3 { animation: qeL3 24s cubic-bezier(0.22, 0.9, 0.3, 1) infinite; }
@keyframes qeL0 { 0%, 8.3% { transform: scale(1); opacity: 1; } 11.8% { opacity: 0; } 13.3% { transform: scale(2.2); opacity: 0; } 75% { transform: scale(2.2); opacity: 0; } 80%, 100% { transform: scale(1); opacity: 1; } }
@keyframes qeL1 { 0%, 8.3% { transform: scale(0.45); opacity: 0; } 13.3% { transform: scale(1); opacity: 1; } 21.7% { transform: scale(1); opacity: 1; } 25.2% { opacity: 0; } 26.7% { transform: scale(2.2); opacity: 0; } 63.7% { transform: scale(2.2); opacity: 0; } 68.7% { transform: scale(1); opacity: 1; } 75% { transform: scale(1); opacity: 1; } 80%, 100% { transform: scale(0.45); opacity: 0; } }
@keyframes qeL2 { 0%, 21.7% { transform: scale(0.45); opacity: 0; } 26.7% { transform: scale(1); opacity: 1; } 35% { transform: scale(1); opacity: 1; } 38.5% { opacity: 0; } 40% { transform: scale(2.2); opacity: 0; } 52.5% { transform: scale(2.2); opacity: 0; } 57.5% { transform: scale(1); opacity: 1; } 63.7% { transform: scale(1); opacity: 1; } 68.7%, 100% { transform: scale(0.45); opacity: 0; } }
@keyframes qeL3 { 0%, 35% { transform: scale(0.45); opacity: 0; } 40% { transform: scale(1); opacity: 1; } 52.5% { transform: scale(1); opacity: 1; } 57.5%, 100% { transform: scale(0.45); opacity: 0; } }
html[data-motion="on"] .sys.live .qe-l0 .qe-target { animation: qemark0 24s linear infinite; }
html[data-motion="on"] .sys.live .qe-l1 .qe-target { animation: qemark1 24s linear infinite; }
html[data-motion="on"] .sys.live .qe-l2 .qe-target { animation: qemark2 24s linear infinite; }
@keyframes qemark0 { 0%, 3% { border-color: rgba(255,255,255,0.4); } 6% { border-color: rgba(255,255,255,0.9); } 13.3%, 100% { border-color: rgba(255,255,255,0.4); } }
@keyframes qemark1 { 0%, 16% { border-color: rgba(255,255,255,0.4); } 19% { border-color: rgba(255,255,255,0.9); } 26.7%, 100% { border-color: rgba(255,255,255,0.4); } }
@keyframes qemark2 { 0%, 30% { border-color: rgba(255,255,255,0.4); } 33% { border-color: rgba(255,255,255,0.9); } 40%, 100% { border-color: rgba(255,255,255,0.4); } }

@media (max-width: 640px) {
  .flow .lane { width: 1px; height: 14px; margin: 4px auto; flex: none; background: linear-gradient(180deg, var(--acc), var(--hair)); }
  .flow .pkt { display: none; }
  html[data-motion="on"] .sys.live .flow .stage { animation: none; }
  .qe-board { height: 220px; }
  .qe-bar .mth { display: none; }
}
