/* ===========================================================================
   NITHEESH.info V3 — shared design system
   One system for every public page: homepage, NASA case study, Contact, 404.
   Authored 2026-09-08. Supersedes site.css / interactive-v2.css / case-v2.css /
   orbital-v3.css on the public boundary.

   Fonts are the existing locally licensed IBM Plex Sans / IBM Plex Mono files
   already vendored under /assets/fonts. No external font request.
   =========================================================================== */

@font-face { font-family: Plex; src: url("../fonts/IBMPlexSans-Regular.ttf") format("truetype"); font-weight: 400; font-display: swap; }
@font-face { font-family: Plex; src: url("../fonts/IBMPlexSans-Medium.ttf") format("truetype"); font-weight: 500; font-display: swap; }
@font-face { font-family: Mono; src: url("../fonts/IBMPlexMono-Regular.ttf") format("truetype"); font-weight: 400; font-display: swap; }

/* --------------------------------------------------------------- tokens -- */
:root {
  /* space: neutral black. The page is the void; stars and the craft are the
     only things that carry colour. */
  --void: #000000;
  --void-deep: #000000;

  /* Neutral translucent charcoal reading surfaces - no blue in the mix, so a
     panel never tints the black behind it. */
  --srf-1: rgb(12 12 12 / .62);
  --srf-2: rgb(12 12 12 / .78);
  --srf-3: rgb(16 16 16 / .88);
  --srf-solid: #0b0b0b;

  /* edges: neutral grey, not blue-grey */
  --edge: rgb(190 190 190 / .13);
  --edge-mid: rgb(190 190 190 / .22);
  --edge-strong: rgb(190 190 190 / .34);

  /* type: near-white primary, neutral grey secondary */
  --ink: #f4f4f5;
  --ink-2: #b2b2b6;
  --ink-3: #7d7d84;

  /* signals — one meaning each */
  --flow: #43d9ff;        /* active data flow */
  --transform: #b18cff;   /* transformation */
  --limit: #e8a24c;       /* documented limits / boundaries */
  --limit-hot: #ff7b72;   /* failed / hard boundary */

  /* geometry */
  --r-sm: 3px;
  --r-md: 5px;
  --r-lg: 9px;
  --r-pill: 999px;

  /* Width of the reserved 3D-assembly gutter in each mobile rail cell. Single
     source of truth: orbital-space.js reads this value (MOBILE_SLOT). */
  --mobile-slot: 96px;

  /* rhythm */
  --s-1: .25rem; --s-2: .5rem; --s-3: .75rem; --s-4: 1rem;
  --s-5: 1.5rem; --s-6: 2rem; --s-7: 3rem; --s-8: 4rem;
  --gut: clamp(1.25rem, 5vw, 5.5rem);
  --section-y: clamp(4.5rem, 9vw, 9rem);
  --measure: 64ch;

  /* motion */
  --ease: cubic-bezier(.22, .75, .28, 1);
  --t-fast: 140ms;
  --t-mid: 240ms;
  --t-slow: 420ms;

  color-scheme: dark;
}

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

html {
  scroll-behavior: smooth;
  background: var(--void);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  overflow-x: hidden;
  color: var(--ink);
  background: transparent;
  font: 400 clamp(.94rem, .35vw + .84rem, 1.03rem)/1.65 Plex, system-ui, sans-serif;
  letter-spacing: .004em;
}

/* the persistent space field lives behind every section on every page */
.space-canvas {
  position: fixed;
  inset: 0;
  z-index: -2;
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 900ms var(--ease);
  pointer-events: none;
}
.space-canvas.is-ready { opacity: 1; }

/* authored static field: always painted, so the page never shows a bare void
   before/instead of WebGL */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -3;
  pointer-events: none;
  /* Flat black. The broad cyan and violet washes that used to live here read as
     a full-screen tint over everything, including the stars. */
  background: var(--void);
}

::selection { background: rgb(67 217 255 / .28); color: #fff; }

:focus-visible {
  outline: 2px solid var(--flow);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

a { color: inherit; }

.skip-link {
  position: fixed;
  z-index: 60;
  top: var(--s-2);
  left: var(--s-2);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-sm);
  background: var(--flow);
  color: #04070e;
  font: 500 .8rem Plex, sans-serif;
  text-decoration: none;
  transform: translateY(-180%);
}
.skip-link:focus { transform: none; }

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

/* ----------------------------------------------------------- typography -- */
h1, h2, h3, h4 {
  margin: 0;
  font-family: Plex, system-ui, sans-serif;
  font-weight: 500;
  letter-spacing: -.035em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.5rem, 5.4vw, 4.6rem); line-height: .96; letter-spacing: -.045em; }
h2 { font-size: clamp(1.9rem, 3.6vw, 3.2rem); line-height: 1.02; }
h3 { font-size: clamp(1.2rem, 1.8vw, 1.6rem); line-height: 1.15; }
p { margin: 0; }

.eyebrow {
  margin: 0;
  color: var(--flow);
  font: 400 .68rem/1 Mono, ui-monospace, monospace;
  letter-spacing: .17em;
  text-transform: uppercase;
}
.mono { font-family: Mono, ui-monospace, monospace; letter-spacing: .04em; }
.lede {
  max-width: 52ch;
  color: var(--ink-2);
  font-size: clamp(1rem, .5vw + .9rem, 1.16rem);
  line-height: 1.62;
}
.note { color: var(--ink-3); font: 400 .74rem/1.5 Mono, monospace; letter-spacing: .05em; }

/* ---------------------------------------------------------------- icons -- */
/* one outlined language: 24-grid, 1.5 stroke, currentColor, never filled */
.icon {
  width: 1em; height: 1em;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -.125em;
}

/* --------------------------------------------------------------- layout -- */
.shell { width: 100%; max-width: 96rem; margin-inline: auto; padding-inline: var(--gut); }
.section { position: relative; padding-block: var(--section-y); }
.section + .section { border-top: 1px solid var(--edge); }

.section-head { max-width: 60rem; display: grid; gap: var(--s-4); }
.section-head h2 { max-width: 18ch; }
.section-head .lede { max-width: 56ch; }

[data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 620ms var(--ease), transform 620ms var(--ease);
}
[data-reveal][data-in-view] { opacity: 1; transform: none; }
html:not(.orbital-js) [data-reveal] { opacity: 1; transform: none; }

/* --------------------------------------------------------------- header -- */
.site-header {
  position: sticky;
  z-index: 30;
  top: 0;
  display: flex;
  gap: var(--s-5);
  align-items: center;
  justify-content: space-between;
  padding: var(--s-3) var(--gut);
  border-bottom: 1px solid var(--edge);
  background: rgb(5 7 13 / .72);
  backdrop-filter: blur(14px);
}
.signature {
  display: inline-flex;
  gap: var(--s-2);
  align-items: center;
  min-height: 44px;
  color: var(--ink);
  font: 500 .74rem Mono, monospace;
  letter-spacing: .12em;
  text-decoration: none;
}
.signature .icon { color: var(--flow); font-size: 1.05rem; }
/* The toggle only exists on narrow viewports; on desktop the nav is always
   open and the button is removed from the accessibility tree entirely. */
.nav-toggle { display: none; }
.site-nav { display: flex; flex-wrap: wrap; gap: var(--s-1); justify-content: flex-end; }
.site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  color: var(--ink-2);
  font: 400 .8rem Plex, sans-serif;
  text-decoration: none;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.site-nav a:hover { color: var(--ink); background: rgb(158 174 200 / .07); }
.site-nav a[aria-current="page"] { color: var(--ink); box-shadow: inset 0 -1px 0 var(--flow); }

/* --------------------------------------------------------------- action -- */
.action {
  display: inline-flex;
  gap: var(--s-2);
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--edge-strong);
  border-radius: var(--r-sm);
  background: var(--srf-2);
  color: var(--ink);
  font: 500 .85rem Plex, sans-serif;
  text-decoration: none;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.action .icon { font-size: 1.05rem; color: var(--ink-3); transition: color var(--t-fast) var(--ease); }
.action:hover, .action:focus-visible {
  border-color: rgb(67 217 255 / .5);
  background: rgb(18 26 40 / .9);
  transform: translateY(-1px);
}
.action:hover .icon, .action:focus-visible .icon { color: var(--flow); }
.action:active { transform: translateY(0); }
.action--primary {
  border-color: transparent;
  background: var(--flow);
  color: #04070e;
}
.action--primary .icon { color: rgb(4 7 14 / .6); }
.action--primary:hover, .action--primary:focus-visible { background: #74e4ff; border-color: transparent; }
.action--primary:hover .icon { color: rgb(4 7 14 / .75); }
.action--quiet { border-color: var(--edge); background: transparent; color: var(--ink-2); }
.action--quiet:hover { color: var(--ink); }

.action-row { display: flex; flex-wrap: wrap; gap: var(--s-2); }
/* two rows (primary + more) that read as one cluster on desktop; the mobile
   hero pulls them apart so the craft can sit between them */
.action-stack { display: flex; flex-direction: column; gap: var(--s-2); }

/* =========================================================== HOME: hero == */
.hero {
  position: relative;
  /* the extra travel drives the ETL transformation; long enough that each of
     the six stages gets real reading distance rather than a flick */
  min-height: calc(100svh + clamp(1200px, 165svh, 2100px));
}
.hero__stage {
  position: sticky;
  top: 0;
  display: grid;
  grid-template-columns: minmax(21rem, 38fr) minmax(0, 62fr);
  grid-template-areas: "copy craft";
  align-items: center;
  gap: clamp(1rem, 2vw, 2rem) clamp(1.5rem, 4vw, 4rem);
  min-height: 100svh;
  padding: clamp(1rem, 3vh, 2.5rem) var(--gut) clamp(1rem, 2.5vh, 2rem);
}
.hero__copy { grid-area: copy; display: grid; gap: var(--s-4); max-width: 44ch; }
.hero__craft { grid-area: craft; position: relative; align-self: stretch;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-3); }

.hero__badge {
  display: inline-flex;
  gap: var(--s-2);
  align-items: center;
  justify-self: start;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--edge);
  border-radius: var(--r-pill);
  background: var(--srf-1);
  backdrop-filter: blur(10px);
  color: var(--ink-2);
  font: 400 .66rem/1 Mono, monospace;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.hero__badge i {
  width: .4rem; height: .4rem;
  border-radius: 50%;
  background: var(--flow);
  box-shadow: 0 0 .5rem var(--flow);
}
.hero h1 span { display: block; }
.hero h1 span + span { color: var(--ink-2); }
.hero__role {
  margin: 0;
  padding-top: var(--s-4);
  border-top: 1px solid var(--edge);
  color: var(--flow);
  font: 400 .76rem/1 Mono, monospace;
  letter-spacing: .2em;
  text-transform: uppercase;
}
.hero__signals {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, auto));
  justify-content: start;
  margin: 0;
}
.hero__signals > div { padding-inline: var(--s-4); border-left: 1px solid var(--edge); }
.hero__signals > div:first-child { padding-left: 0; border-left: 0; }
.hero__signals dt { color: var(--ink-3); font: 400 .58rem/1 Mono, monospace; letter-spacing: .12em; text-transform: uppercase; }
.hero__signals dd { margin: var(--s-2) 0 0; color: var(--ink); font: 500 .95rem/1.2 Plex, sans-serif; }

/* craft box: the renderer maps the spacecraft into exactly this rectangle, so
   it can never cross the name or the action rail */
.craft-box {
  position: relative;
  min-height: clamp(15rem, 42vh, 28rem);
  border-radius: var(--r-lg);
  touch-action: pan-y;                 /* vertical scrolling always wins */
  cursor: grab;
}
.craft-box:active { cursor: grabbing; }
html:not(.orbital-renderer-ready) .craft-box { cursor: default; }
.craft-box::after {
  content: "";
  position: absolute;
  inset: 6% 2%;
  border-radius: 40%;
  background:
    radial-gradient(ellipse 58% 54% at 52% 46%, rgb(255 255 255 / .035), transparent 70%);
  filter: blur(28px);
  pointer-events: none;
  z-index: -1;
}

.craft-tools {
  position: absolute;
  right: 0;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  align-items: center;
}
/* the hint is a first-run affordance; keep it from forcing the control row to
   wrap on a narrow craft column */
.craft-tools .craft-hint { margin-right: auto; }
.craft-hint {
  color: var(--ink-3);
  font: 400 .62rem/1 Mono, monospace;
  letter-spacing: .08em;
  text-transform: uppercase;
}
html:not(.orbital-renderer-ready) .craft-tools { display: none; }

.btn-quiet {
  display: inline-flex;
  gap: var(--s-2);
  align-items: center;
  min-height: 44px;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--edge-mid);
  border-radius: var(--r-sm);
  background: var(--srf-2);
  color: var(--ink-2);
  font: 400 .7rem Mono, monospace;
  letter-spacing: .06em;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.btn-quiet:hover { color: var(--ink); border-color: var(--flow); }

/* static fallback drawing, shown until (or instead of) WebGL */
.craft-fallback {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 1;
  transition: opacity 600ms var(--ease);
}
.orbital-renderer-ready .craft-fallback { opacity: 0; }
.craft-fallback .cf-body { fill: rgb(158 174 200 / .07); stroke: var(--ink-2); stroke-width: 1.2; }
.craft-fallback .cf-panel { fill: rgb(20 30 60 / .55); stroke: rgb(67 217 255 / .5); stroke-width: 1.2; }
.craft-fallback .cf-line { fill: none; stroke: var(--flow); stroke-width: 1.2; }
.craft-fallback .cf-dim { fill: none; stroke: rgb(158 174 200 / .3); stroke-width: 1; }
.craft-fallback text { fill: var(--ink-3); font: 400 11px Mono, monospace; letter-spacing: .08em; }

/* ------------------------------------------------------------- ETL rail -- */
.etl-rail {
  /* The rail lives INSIDE the craft column now. It must not claim a named grid
     area: `grid-area: rail` against a parent that defines no such area creates
     an implicit second column, which on mobile squeezed the renderer's stage
     box from 350px down to 44px. */
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1px;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: var(--srf-1);
  backdrop-filter: blur(14px);
  list-style: none;
}
.etl-rail > li { position: relative; min-width: 0; }
.etl-rail > li + li { box-shadow: -1px 0 0 var(--edge); }
.etl-rail > li::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 2px;
  background: var(--flow);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-slow) var(--ease), opacity var(--t-mid) var(--ease);
}
.etl-rail > li[data-passed]::before { transform: scaleX(1); opacity: .32; }
.etl-rail > li[data-active]::before { transform: scaleX(1); opacity: 1; }
.etl-rail > li[data-active] { background: linear-gradient(180deg, rgb(67 217 255 / .1), transparent 80%); }
.etl-rail > li[data-selected] { background: linear-gradient(180deg, rgb(177 140 255 / .14), transparent 80%); }

.stage-btn {
  display: grid;
  align-content: start;
  gap: var(--s-1);
  width: 100%;
  min-height: 76px;
  padding: var(--s-3);
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.stage-btn > .idx { color: var(--ink-3); font: 400 .56rem/1 Mono, monospace; letter-spacing: .12em; }
/* Stage names and the subsystem they map to are the substance of the diagram,
   so neither may be clipped. They wrap at spaces and the cell grows to fit -
   but they are LABELS, not prose, so they never hyphenate or break inside a
   word: "Ingest & Validate" must never render as "Ingest / & / Validate". */
.stage-btn > .name {
  color: var(--ink-2);
  font: 500 .78rem/1.2 Plex, sans-serif;
  overflow-wrap: normal;
  word-break: keep-all;
  hyphens: none;
  transition: color var(--t-mid) var(--ease);
}
.stage-btn > .sub {
  color: var(--ink-3);
  font: 400 .6rem/1.3 Mono, monospace;
  overflow-wrap: normal;
}
li[data-active] .stage-btn > .name { color: var(--ink); }
li[data-active] .stage-btn > .idx { color: var(--flow); }
li[data-selected] .stage-btn > .idx { color: var(--transform); }
.stage-btn:hover > .name { color: var(--ink); }
/* the cell owns the height; let the button fill it so the active/selected
   tint and the hit target both cover the whole cell */
.etl-rail > li { display: flex; }
.etl-rail .stage-btn { flex: 1; }

/* ==================================================== HOME: ETL section == */
.pipeline {
  display: grid;
  /* Six cards, explicitly balanced. auto-fit produced 5 across + 1 orphan and a
     large empty panel on wide screens. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  margin: var(--s-7) 0 0;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: var(--edge);
  list-style: none;
}
.pipeline > li {
  position: relative;
  display: grid;
  align-content: start;
  gap: var(--s-2);
  padding: var(--s-5);
  background: var(--srf-3);
}
.pipeline .idx { color: var(--flow); font: 400 .6rem/1 Mono, monospace; letter-spacing: .14em; }
.pipeline h3 { font-size: 1.02rem; letter-spacing: -.015em; }
.pipeline p { color: var(--ink-2); font-size: .87rem; line-height: 1.55; }
.pipeline .attrib {
  margin-top: var(--s-1);
  color: var(--ink-3);
  font: 400 .64rem/1.45 Mono, monospace;
  letter-spacing: .03em;
}
/* connection to the next stage — direction of processing */
.pipeline > li:not(:last-child)::after {
  content: "";
  position: absolute;
  top: var(--s-5);
  right: -1px;
  width: 1px;
  height: 2.2rem;
  background: linear-gradient(180deg, var(--flow), transparent);
}

/* ================================================== HOME: project cards == */
.projects { display: grid; gap: var(--s-5); margin-top: var(--s-7); }

.project {
  position: relative;
  display: grid;
  gap: clamp(1.25rem, 3vw, 3rem);
  padding: clamp(1.25rem, 2.6vw, 2.5rem);
  overflow: hidden;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: linear-gradient(140deg, rgb(20 28 44 / .5), var(--srf-3) 62%);
  transition: border-color var(--t-mid) var(--ease);
}
.project:hover, .project:focus-within { border-color: var(--edge-mid); }
.project--flagship { grid-template-columns: minmax(16rem, 5fr) minmax(18rem, 7fr); }
.project--flagship::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: linear-gradient(90deg, var(--flow), rgb(177 140 255 / .5) 46%, transparent 80%);
}
.project__art {
  position: absolute;
  right: -6%;
  bottom: -24%;
  z-index: 0;
  width: min(28rem, 42%);
  opacity: .12;
  mask-image: radial-gradient(ellipse at 50% 50%, #000 18%, transparent 72%);
  pointer-events: none;
}
.project > * { position: relative; z-index: 1; }
.project__head { display: grid; gap: var(--s-3); align-content: start; }
.project__kicker { color: var(--transform); font: 400 .68rem/1.5 Mono, monospace; letter-spacing: .04em; }
.project__scope {
  justify-self: start;
  padding: var(--s-1) var(--s-3);
  border: 1px solid rgb(67 217 255 / .3);
  border-radius: var(--r-pill);
  color: var(--flow);
  font: 400 .6rem/1.6 Mono, monospace;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.project__body { display: grid; gap: var(--s-5); align-content: start; }

/* lineage: the hero pipeline continued into project evidence */
.lineage { display: grid; gap: 0; margin: 0; padding-left: var(--s-5); border-left: 1px solid var(--edge); list-style: none; }
.lineage > li { position: relative; padding-block: var(--s-2); }
.lineage > li::before {
  content: "";
  position: absolute;
  top: .95rem;
  left: calc(var(--s-5) * -1 - 4px);
  width: 7px; height: 7px;
  border: 1px solid var(--flow);
  border-radius: 50%;
  background: var(--void);
}
.lineage > li:last-child::before { background: var(--flow); }
.lineage span { display: block; color: var(--ink-3); font: 400 .56rem/1 Mono, monospace; letter-spacing: .13em; text-transform: uppercase; }
.lineage strong { display: block; margin-top: var(--s-1); color: var(--ink); font: 400 .87rem/1.4 Plex, sans-serif; }

.metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 1px;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--edge);
  border-radius: var(--r-sm);
  background: var(--edge);
}
.metrics > div { padding: var(--s-3); background: var(--srf-solid); }
.metrics dt { color: var(--ink-3); font: 400 .55rem/1 Mono, monospace; letter-spacing: .11em; text-transform: uppercase; }
.metrics dd { margin: var(--s-2) 0 0; color: var(--ink); font: 500 1.24rem/1 Plex, sans-serif; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.metrics dd span { display: block; margin-top: var(--s-1); color: var(--ink-3); font: 400 .6rem/1.35 Mono, monospace; }

.limit-note {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  align-items: baseline;
  padding: var(--s-3);
  border: 1px solid rgb(232 162 76 / .32);
  border-left: 2px solid var(--limit);
  border-radius: var(--r-sm);
  background: rgb(232 162 76 / .05);
  color: var(--ink-2);
  font-size: .85rem;
}
.limit-note strong { color: var(--limit); font: 400 .58rem/1.6 Mono, monospace; letter-spacing: .12em; text-transform: uppercase; }

/* supporting projects */
.project--support { grid-template-columns: minmax(0, 1fr); }
.projects__pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: var(--s-5); }
.project--support h3 { font-size: 1.35rem; }
.evidence-line { color: var(--flow); font: 400 .68rem/1.6 Mono, monospace; letter-spacing: .04em; }

/* disclosure */
.disclose { border-top: 1px solid var(--edge); }
.disclose > summary {
  display: flex;
  gap: var(--s-2);
  align-items: center;
  min-height: 46px;
  color: var(--ink-2);
  font: 400 .74rem Mono, monospace;
  letter-spacing: .07em;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
  transition: color var(--t-fast) var(--ease);
}
.disclose > summary::-webkit-details-marker { display: none; }
.disclose > summary:hover { color: var(--ink); }
.disclose > summary .icon { transition: transform var(--t-mid) var(--ease); color: var(--flow); }
.disclose[open] > summary .icon { transform: rotate(90deg); }
.disclose__body { display: grid; gap: var(--s-3); padding-bottom: var(--s-4); color: var(--ink-2); font-size: .88rem; }

/* ==================================================== HOME: capabilities = */
/* Seven working patterns. A fixed column count with the last item spanning its
   row keeps every cell filled — no orphaned dead cell at any width. */
.capabilities { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; margin-top: var(--s-7); padding: 0; overflow: hidden; border: 1px solid var(--edge); border-radius: var(--r-md); background: var(--edge); list-style: none; }
.capability:last-child { grid-column: 1 / -1; }
@media (max-width: 900px) { .capabilities { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .capabilities { grid-template-columns: minmax(0, 1fr); } }
.capability { display: grid; align-content: start; gap: var(--s-2); padding: var(--s-5); background: var(--srf-3); transition: background var(--t-mid) var(--ease); }
.capability:hover { background: rgb(20 27 41 / .92); }
.capability__head { display: flex; gap: var(--s-2); align-items: center; color: var(--flow); font: 400 .6rem/1 Mono, monospace; letter-spacing: .13em; text-transform: uppercase; }
.capability h3 { font-size: 1.02rem; }
.capability p { color: var(--ink-2); font-size: .86rem; line-height: 1.6; }

/* ========================================================== HOME: career = */
.career { display: grid; gap: 0; margin: var(--s-7) 0 0; padding: 0; list-style: none; }
.career > li { display: grid; grid-template-columns: minmax(7rem, 12%) 1fr; gap: clamp(1rem, 3vw, 3rem); padding-block: var(--s-5); border-top: 1px solid var(--edge); }
.career > li:last-child { border-bottom: 1px solid var(--edge); }
.career time { color: var(--flow); font: 400 .68rem/1.6 Mono, monospace; letter-spacing: .08em; }
.career h3 { font-size: 1.1rem; }
.career p { margin-top: var(--s-2); color: var(--ink-2); font-size: .9rem; }
.education { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin-top: var(--s-5); color: var(--ink-2); font-size: .9rem; }
.education strong { color: var(--ink); font-weight: 500; }

/* ================================================= HOME: web experiences = */
.experience {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: center;
  margin-top: var(--s-7);
  padding: clamp(1.5rem, 3vw, 2.75rem);
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: linear-gradient(130deg, rgb(20 28 44 / .45), var(--srf-3) 66%);
}
.experience__mark {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  max-width: 14rem;
  border: 1px solid rgb(67 217 255 / .2);
  border-radius: 50%;
}
.experience__mark::before, .experience__mark::after {
  content: "";
  position: absolute;
  border: 1px solid var(--edge-mid);
  border-radius: 50%;
}
.experience__mark::before { inset: 14% -6%; transform: rotate(-22deg); }
.experience__mark::after { inset: -4% 22%; transform: rotate(36deg); }
.experience__mark span { color: var(--flow); font: 400 .66rem Mono, monospace; letter-spacing: .18em; }
.experience__copy { display: grid; gap: var(--s-3); }

/* ====================================================== HOME: conversion = */
.conversion { display: grid; gap: var(--s-5); padding-block: var(--section-y); text-align: left; }
.conversion h2 { max-width: 20ch; }

/* --------------------------------------------------------------- footer -- */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  justify-content: space-between;
  padding: var(--s-6) var(--gut);
  border-top: 1px solid var(--edge);
  color: var(--ink-3);
  font-size: .82rem;
}
.site-footer a { color: var(--ink-2); text-decoration: none; }
.site-footer a:hover { color: var(--ink); }

/* ===================================================== NASA CASE STUDY === */
.case-hero { padding-block: clamp(3.5rem, 8vw, 7rem) var(--s-7); }
.case-hero h1 { max-width: 16ch; }
.case-hero .lede { margin-top: var(--s-5); max-width: 58ch; font-size: clamp(1.05rem, .6vw + .95rem, 1.3rem); }
.state-strip { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-6); }
.state-chip {
  display: inline-flex;
  gap: var(--s-2);
  align-items: center;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--edge-mid);
  border-radius: var(--r-pill);
  color: var(--ink-2);
  font: 400 .66rem/1 Mono, monospace;
  letter-spacing: .07em;
}
.state-chip--ok { border-color: rgb(67 217 255 / .38); color: var(--flow); }
.state-chip--limit { border-color: rgb(232 162 76 / .4); color: var(--limit); }

.case-nav {
  position: sticky;
  z-index: 20;
  top: 61px;
  display: flex;
  overflow-x: auto;
  gap: var(--s-1);
  padding: var(--s-2) var(--gut);
  border-block: 1px solid var(--edge);
  background: rgb(5 7 13 / .85);
  backdrop-filter: blur(14px);
  scrollbar-width: none;
}
.case-nav::-webkit-scrollbar { display: none; }
.case-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  color: var(--ink-2);
  font: 400 .7rem Mono, monospace;
  letter-spacing: .06em;
  text-decoration: none;
  white-space: nowrap;
}
.case-nav a:hover { color: var(--ink); background: rgb(158 174 200 / .08); }

.case-section { padding-block: var(--section-y); border-top: 1px solid var(--edge); }
.case-section > .shell { display: grid; gap: var(--s-5); }
.case-section p { max-width: var(--measure); color: var(--ink-2); }
.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); gap: clamp(1.5rem, 4vw, 3.5rem); }
.tech-line { color: var(--flow); font: 400 .7rem/1.9 Mono, monospace; letter-spacing: .05em; }

.metric-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: 1px; margin: 0; overflow: hidden; border: 1px solid var(--edge); border-radius: var(--r-md); background: var(--edge); }
.metric-grid > div { display: grid; align-content: start; gap: var(--s-2); padding: var(--s-5); background: var(--srf-3); }
.metric-grid dt { color: var(--ink-3); font: 400 .58rem/1 Mono, monospace; letter-spacing: .11em; text-transform: uppercase; }
.metric-grid dd { margin: 0; color: var(--ink); font: 500 clamp(1.5rem, 2.4vw, 2.2rem)/1 Plex, sans-serif; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
.metric-grid p { color: var(--ink-3); font-size: .78rem; line-height: 1.45; }

.flow-steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 1px; margin: 0; padding: 0; overflow: hidden; border: 1px solid var(--edge); border-radius: var(--r-md); background: var(--edge); list-style: none; }
.flow-steps > li { display: grid; align-content: start; gap: var(--s-2); padding: var(--s-5); background: var(--srf-3); }
.flow-steps strong { color: var(--flow); font: 400 .62rem/1 Mono, monospace; letter-spacing: .13em; text-transform: uppercase; }
.flow-steps .what { color: var(--ink); font: 500 .95rem/1.35 Plex, sans-serif; }
.flow-steps p { color: var(--ink-2); font-size: .84rem; }

.divergence { display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); gap: 1px; overflow: hidden; border: 1px solid var(--edge); border-radius: var(--r-md); background: var(--edge); }
.divergence > div { display: grid; align-content: start; gap: var(--s-3); padding: var(--s-5); background: var(--srf-3); }
.state-label { font: 400 .62rem/1 Mono, monospace; letter-spacing: .13em; text-transform: uppercase; }
.divergence--passed .state-label { color: var(--flow); }
.divergence--failed .state-label { color: var(--limit-hot); }
.divergence--failed { box-shadow: inset 2px 0 0 var(--limit-hot); }
.divergence--passed { box-shadow: inset 2px 0 0 var(--flow); }

.limits { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; max-width: var(--measure); }
.limits > li { padding-block: var(--s-3); border-top: 1px solid var(--edge); color: var(--ink-2); font-size: .92rem; }
.limits > li:last-child { border-bottom: 1px solid var(--edge); }
.limits > li::marker { content: none; }

/* ============================================================== CONTACT == */
.contact-main { display: grid; align-content: center; min-height: calc(100svh - 61px); padding-block: var(--section-y); }
.contact-main h1 { max-width: 14ch; }
.contact-main .lede { margin-top: var(--s-5); font-size: clamp(1.05rem, .6vw + .95rem, 1.3rem); }
.contact-meta { display: grid; gap: var(--s-2); margin-top: var(--s-7); padding-left: var(--s-4); border-left: 2px solid var(--limit); color: var(--ink-2); font-size: .9rem; }

/* ================================================================== 404 == */
.notfound-main { display: grid; align-content: center; min-height: calc(100svh - 61px); padding-block: var(--section-y); }
.notfound-main h1 { max-width: 12ch; }

/* =============================================================== MOBILE == */
@media (max-width: 900px) {
  .hero { min-height: auto; }
  /* One interleaved column: identity, the two primary actions and the craft
     share the opening; Selected Work / LinkedIn / GitHub, the annotation and the
     rail follow below the model. The two layout wrappers collapse so their
     children can be ordered as one list. */
  .hero__stage {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: stretch;          /* base rule is align-items:center — undo it */
    grid-template-areas: none;
    min-height: 0;
    padding: var(--s-5) var(--gut) var(--s-6);
    gap: var(--s-5);
  }
  .hero__copy, .hero__craft, .action-stack { display: contents; }
  .hero__badge      { order: 1; }
  .hero h1          { order: 2; }
  .hero__role       { order: 3; }
  .hero .lede       { order: 4; }
  .hero__signals    { order: 5; }
  .action-row       { order: 6; }        /* Contact + Request Résumé */
  .craft-box        { order: 7; }
  .craft-tools      { order: 8; }
  .action-row--more { order: 9; }        /* Selected Work / LinkedIn / GitHub */
  .acq-note         { order: 10; }
  .etl-rail         { order: 11; }
  .craft-hint, [data-inspect-status], #craft-desc, .etl-caption { order: 12; }
  /* contrast shield behind the identity block (the collapsed .hero__copy can no
     longer carry its own ::before) */
  .hero__stage::before {
    content: "";
    position: absolute;
    inset: -1rem -1rem auto -1rem;
    height: min(58%, 30rem);
    z-index: -1;
    pointer-events: none;
    background: radial-gradient(125% 78% at 28% 24%, rgb(0 0 0 / .82), rgb(0 0 0 / 0) 74%);
  }

  .hero__copy { max-width: none; }
  .hero h1 { font-size: clamp(2rem, 9.6vw, 3rem); line-height: .98; }
  .hero h1 span { white-space: nowrap; }
  .hero__badge { font-size: .56rem; letter-spacing: .07em; }
  .hero__signals { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .hero__signals > div { padding-inline: var(--s-3); }
  .hero__signals > div:first-child { padding-left: 0; }
  .hero__signals dd { font-size: .82rem; }
  .action-row { display: grid; grid-template-columns: 1fr 1fr; }
  .craft-box { min-height: min(72vw, 19rem); }
  .craft-tools { position: static; justify-content: flex-end; flex-wrap: wrap; margin-top: 0; }

  /* vertical pipeline: larger labels, native scroll, no sideways travel */
  .etl-rail { grid-template-columns: 1fr; }
  .etl-rail > li + li { box-shadow: 0 -1px 0 var(--edge); }
  .etl-rail > li::before { inset: 0 auto 0 0; width: 2px; height: auto; transform: scaleY(0); transform-origin: top; }
  .etl-rail > li[data-passed]::before, .etl-rail > li[data-active]::before { transform: scaleY(1); }
  .stage-btn { min-height: 56px; }
  .stage-btn > .name { font-size: .92rem; white-space: normal; }
  .stage-btn > .sub { font-size: .68rem; white-space: normal; }

  .project--flagship { grid-template-columns: 1fr; }
  .project__art { display: none; }
  .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .experience { grid-template-columns: 1fr; }
  .experience__mark { max-width: 11rem; margin-inline: auto; }
  .career > li { grid-template-columns: 1fr; gap: var(--s-2); }
  /* Usable mobile navigation: a real disclosure button and a panel, instead of
     hiding the links with no way to reach them. */
  .nav-toggle {
    display: inline-flex;
    gap: var(--s-2);
    align-items: center;
    min-height: 44px;
    min-width: 44px;
    padding: var(--s-2) var(--s-3);
    border: 1px solid var(--edge-mid);
    border-radius: var(--r-sm);
    background: var(--srf-2);
    color: var(--ink-2);
    font: 400 .7rem Mono, monospace;
    letter-spacing: .06em;
    cursor: pointer;
  }
  .nav-toggle[aria-expanded="true"] { color: var(--flow); border-color: var(--flow); }
  .site-nav {
    position: absolute;
    inset: 100% var(--gut) auto var(--gut);
    z-index: 40;
    display: none;
    flex-direction: column;
    gap: 0;
    padding: var(--s-2);
    border: 1px solid var(--edge-strong);
    border-radius: var(--r-md);
    background: var(--srf-solid);
    box-shadow: 0 18px 44px rgb(0 0 0 / .55);
  }
  .site-nav[data-open] { display: flex; }
  .site-nav a {
    min-height: 48px;
    display: flex;
    align-items: center;
    padding-inline: var(--s-3);
  }
  .site-nav a + a { box-shadow: inset 0 1px 0 var(--edge); }
  .site-header { position: relative; padding-inline: var(--gut); }
  .case-nav { top: 57px; }
  .pipeline > li:not(:last-child)::after { display: none; }
}

@media (max-width: 380px) {
  .action-row { grid-template-columns: 1fr; }
  .hero__signals { grid-template-columns: 1fr 1fr; row-gap: var(--s-3); }
  .hero__signals > div:nth-child(3) { grid-column: 1 / -1; padding-left: 0; border-left: 0; }
  .metrics { grid-template-columns: 1fr; }
  .hero h1 { font-size: clamp(1.85rem, 9vw, 2.5rem); }
}

/* ============================================================ A11Y MODES = */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .space-canvas { display: none; }
  .craft-fallback { opacity: 1 !important; }
}

@media (forced-colors: active) {
  body::before, .craft-box::after, .project__art { display: none; }
  .space-canvas { display: none; }
  .craft-fallback { opacity: 1 !important; }
  .action, .btn-quiet, .pipeline, .metrics, .metric-grid, .etl-rail, .project,
  .capabilities, .experience, .flow-steps, .divergence, .limit-note, .state-chip {
    border-color: CanvasText;
    background: Canvas;
  }
  .etl-rail > li[data-active] { background: Highlight; color: HighlightText; }
  .craft-fallback * { stroke: CanvasText !important; fill: none !important; }
}

/* WebGL refused or unavailable: the authored drawing stays, nothing is blank */
.orbital-renderer-unavailable .space-canvas { display: none; }
.orbital-renderer-unavailable .craft-fallback,
.orbital-renderer-static .craft-fallback { opacity: 1; }

/* narrow phones: keep the signal labels on one line each */
@media (max-width: 430px) {
  .hero__signals dt { font-size: .46rem; letter-spacing: .08em; }
  .hero__signals > div { padding-inline: var(--s-2); }
  .hero__signals dd { font-size: .76rem; }
}

/* ===========================================================================
   Evidence components — consistent card grammar across projects, experiences
   and career. Structure adapted from a reviewed reference portfolio; theme,
   colour and content remain this site's own.
   =========================================================================== */

/* key/value attribute chip: dim mono key, brighter value */
.attrs { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: 0; padding: 0; }
.attr {
  display: inline-flex;
  gap: var(--s-2);
  align-items: baseline;
  padding: var(--s-1) var(--s-3);
  border: 1px solid var(--edge);
  border-radius: var(--r-sm);
  background: rgb(158 174 200 / .05);
  font: 400 .64rem/1.7 Mono, ui-monospace, monospace;
  letter-spacing: .06em;
}
.attr b { color: var(--ink-3); font-weight: 400; text-transform: uppercase; }
.attr span { color: var(--ink); }
.attr--limit { border-color: rgb(232 162 76 / .35); background: rgb(232 162 76 / .06); }
.attr--limit b { color: var(--limit); }

/* technology tag — always scoped to one project, never a global keyword wall */
.tags { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: 0; padding: 0; list-style: none; }
.tags > li {
  padding: var(--s-1) var(--s-3);
  border: 1px solid var(--edge-mid);
  border-radius: var(--r-sm);
  background: var(--srf-solid);
  color: var(--ink-2);
  font: 400 .68rem/1.6 Mono, ui-monospace, monospace;
  letter-spacing: .02em;
}
.tags--flow > li { border-color: rgb(67 217 255 / .26); color: var(--flow); }

/* status pill with a live dot */
.status {
  display: inline-flex;
  gap: var(--s-2);
  align-items: center;
  padding: var(--s-1) var(--s-3);
  border: 1px solid rgb(67 217 255 / .32);
  border-radius: var(--r-sm);
  color: var(--flow);
  font: 400 .62rem/1.6 Mono, monospace;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
}
.status i { width: .38rem; height: .38rem; border-radius: 50%; background: var(--flow); }

/* card footer: category on the left, actions on the right */
.card-foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
  justify-content: space-between;
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--edge);
}
.card-foot__label { color: var(--ink-3); font: 400 .62rem/1 Mono, monospace; letter-spacing: .16em; text-transform: uppercase; }
.card-foot .action-row { gap: var(--s-2); }
.card-foot .action { min-height: 44px; padding: var(--s-2) var(--s-3); font-size: .78rem; }

/* title row: heading left, status right */
.title-row { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: flex-start; justify-content: space-between; }

/* impact line: one labelled summary of scope, mirroring the evidence line */
.impact {
  display: grid;
  gap: var(--s-1);
  padding-left: var(--s-4);
  border-left: 2px solid var(--transform);
  color: var(--ink-2);
  font-size: .88rem;
  line-height: 1.6;
}
.impact b { color: var(--transform); font: 400 .58rem/1.6 Mono, monospace; letter-spacing: .14em; text-transform: uppercase; }

/* detail bullets inside disclosures */
.detail-list { display: grid; gap: var(--s-2); margin: 0; padding-left: var(--s-5); color: var(--ink-2); font-size: .87rem; line-height: 1.55; }
.detail-list > li::marker { color: var(--flow); }

@media (max-width: 900px) {
  .card-foot { align-items: stretch; flex-direction: column; }
  .card-foot .action-row { display: grid; grid-template-columns: 1fr 1fr; }
}

/* the decorative project art must stay out of flow: the generic `.project > *`
   stacking rule would otherwise promote it to a grid item and push the card
   content into the wrong column */
.project > .project__art { position: absolute; z-index: 0; }

/* ---- ETL rail now lives inside the craft column: one aligned diagram ------ */
@media (min-width: 901px) {
  .hero__stage { grid-template-areas: "copy craft"; grid-template-rows: minmax(0, 1fr); }
  /* top-align the craft column and clear the sticky header, so the diagram
     caption is never tucked behind it while the hero is stuck */
  .hero__craft { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; gap: var(--s-3); align-content: start; padding-top: 3.25rem; }
}
.craft-tools { position: static; justify-content: flex-end; margin-top: var(--s-2); }

/* explicit motion control state */
[data-motion-paused] .space-canvas { opacity: .85; }
[data-motion-paused] [data-reveal] { transition: none; }
.btn-quiet[aria-pressed="true"] { border-color: var(--flow); color: var(--flow); }

/* the craft column carries the box, its tools and the rail: keep all three
   inside the sticky stage so the diagram is never cut off by the fold */
@media (min-width: 901px) {
  .craft-box { min-height: 0; height: 100%; }
  .hero__craft { min-height: 0; }
  .etl-rail .stage-btn { min-height: 60px; padding: var(--s-2) var(--s-3); }
  html.has-orbital-v3 .hero__stage, .hero__stage { align-content: center; }
}

/* the sticky stage sits under a ~68px sticky header; 100svh overflowed the
   fold and clipped the pipeline rail */
@media (min-width: 901px) {
  .hero__stage { min-height: calc(100svh - 4.25rem); }
}


/* ---------------------------------------------------------- motion control --
   The animated space field runs on every page, so the pause control must be
   reachable on every page - not only the homepage hero that happens to own a
   craft toolbar. */
.motion-dock {
  position: fixed;
  right: var(--s-3);
  bottom: var(--s-3);
  z-index: 45;
}
.motion-dock .btn-quiet { background: var(--srf-solid); }
html:not(.orbital-renderer-ready) .motion-dock { display: none; }

/* On mobile the field runs behind a full-width layout, so a floating dock would
   sit over the rail or the footer at some scroll position. Instead the pause
   control lives inline in the footer - always reachable, never an overlay on
   stage text or interactive content at any scroll position. */
@media (max-width: 900px) {
  .motion-dock {
    position: static;
    display: flex;
    justify-content: flex-end;
    padding: 0 var(--gut) var(--s-6);
  }
  .motion-dock .btn-quiet { min-height: 44px; }
}
@media (prefers-reduced-motion: reduce) { .motion-dock { display: none; } }

/* Inspection is disabled while the pipeline is resolving, so stop promising it.
   The hint is decorative; the accessible name on the surface carries the truth. */
.craft-box[data-inspect="off"] { cursor: default; }
.craft-hint[hidden] { display: none; }

/* ------------------------------------------------ ETL: four clear regions --
   The craft box is the ASSEMBLY DISPLAY REGION, the rail is the LABEL REGION,
   and these ticks are the CONNECTOR REGION between them. The controls sit in
   their own row. Nothing is drawn behind a label or a button. */
@media (min-width: 901px) {
  .etl-rail > li { padding-top: 14px; }
  /* one connector per stage, rising from the label toward its assembly */
  .etl-rail > li::after {
    content: "";
    position: absolute;
    left: 50%;
    top: -18px;
    width: 1px;
    height: 18px;
    background: linear-gradient(180deg, rgb(67 217 255 / 0), rgb(67 217 255 / .45));
    opacity: 0;
    transition: opacity var(--t-mid) var(--ease);
  }
  [data-stage-engaged] .etl-rail > li::after { opacity: .8; }
  [data-stage-engaged] .etl-rail > li[data-active]::after {
    background: linear-gradient(180deg, rgb(177 140 255 / 0), var(--transform));
    opacity: 1;
  }
}

/* Reading surfaces: translucent neutral charcoal over the field, never an
   opaque navy slab, and never lowered text opacity to look futuristic. */
/* No backdrop blur here: it blurred and dimmed whatever 3D sat behind the rail,
   which made any assembly incursion read as the labels covering the model. The
   surface token alone keeps the text readable. */
.etl-rail { background: var(--srf-2); }
.craft-tools { position: relative; z-index: 4; }

/* ETL rail legibility, all desktop widths: every cell reserves two lines for the
   name and two for the subsystem, so the six cells are the same height and the
   rail reads as an even strip at any width — "Ingest & Validate" wrapping to two
   lines then reads deliberate, not broken. The column count never changes, so
   scrolling never reflows the selector (ledger 33). */
@media (min-width: 901px) {
  .stage-btn > .name { min-block-size: 2.35em; }
  .stage-btn > .sub  { min-block-size: 2.6em; }
}
/* Below ~1400px the six columns are narrow enough that the long names wrap.
   Keep the type close to full reading size (0.76 vs 0.78rem base) and only trim
   padding — this is NOT a shrink-to-fit pass, the two-line rows above do the work. */
@media (min-width: 901px) and (max-width: 1400px) {
  .etl-rail .stage-btn { padding: 10px 7px; min-height: 58px; gap: 3px; }
  .stage-btn > .idx  { font-size: .52rem; }
  .stage-btn > .name { font-size: .76rem; line-height: 1.2; }
  .stage-btn > .sub  { font-size: .6rem; line-height: 1.3; }
}
/* The tightest desktop band: cells are ~72px wide and the subsystem line runs
   to three rows. Reserve three rows for EVERY cell so the six stay level. */
@media (min-width: 901px) and (max-width: 1080px) {
  .stage-btn > .sub { min-block-size: 3.7em; }
}

/* The hero controls float over the live 3D. Back them with a near-opaque
   surface so the Earth limb or a passing subsystem can never bleed through the
   "Reset view" / "Pause motion" label and make the control hard to read. */
@media (min-width: 901px) {
  .craft-tools .btn-quiet,
  .motion-dock .btn-quiet { background: var(--srf-3); }
}

/* keep the brightest dust away from the copy column without dimming the text */
.hero__copy { position: relative; z-index: 2; }
.hero__copy::before {
  content: "";
  position: absolute;
  inset: -3rem -4rem -3rem -6rem;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(78% 62% at 34% 50%, rgb(0 0 0 / .84), rgb(0 0 0 / 0) 72%);
}
@media (max-width: 900px) {
  /* .hero__copy is display:contents here, so its shield moves to .hero__stage
     (see the mobile hero block). Neutralise the inherited pseudo-element. */
  .hero__copy::before { display: none; }
}
.hero, .section { overflow-x: clip; }

/* --------------------------------------------- resolved diagram, one block --
   Heading, assembly display, connectors, labels and controls read as a single
   titled section once the transformation engages. */
.etl-caption {
  margin: 0 0 var(--s-2);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
  pointer-events: none;
}
.etl-caption { position: relative; z-index: 4; }
.etl-caption span {
  display: block;
  font: 400 .62rem Mono, monospace;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--flow);
}
.etl-caption strong {
  display: block;
  margin-top: .25rem;
  font: 600 1.35rem/1.1 Plex, sans-serif;
  letter-spacing: -.01em;
  color: var(--ink);
}
[data-stage-engaged] .etl-caption { opacity: 1; transform: none; }
@media (max-width: 900px) { .etl-caption { display: none; } }
@media (prefers-reduced-motion: reduce) { .etl-caption { transition: none; } }

/* ---------------------------------------------- acquisition annotation ------
   Illustrative-science label, distinct from project evidence. Visible only in
   the acquisition beat (p 0.17-0.34). On desktop it overlays the lower-left of
   the scene where the footprint sits; on mobile it is a static caption. Always
   in the accessibility tree — it is one short, true, clearly-labelled line. */
.acq-note {
  margin: 0;
  color: var(--ink-2);
  font-size: .8rem;
  line-height: 1.5;
  max-width: 30ch;
}
.acq-note__tag {
  display: block;
  margin-bottom: .35rem;
  color: var(--limit);
  font: 400 .58rem/1 Mono, monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
}
@media (min-width: 901px) {
  .acq-note {
    position: absolute;
    left: 0;
    top: 38%;
    z-index: 3;
    padding: var(--s-3) var(--s-4);
    border-left: 2px solid var(--limit);
    background: linear-gradient(90deg, rgb(0 0 0 / .82), rgb(0 0 0 / 0) 96%);
    opacity: 0;
    transform: translateY(6px);
    transition: opacity var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
    pointer-events: none;
  }
  .hero[data-beat="acquisition"] .acq-note { opacity: 1; transform: none; }
}
@media (max-width: 900px) {
  .acq-note {
    padding: var(--s-3) 0 0;
    border-top: 1px solid var(--edge);
  }
}
@media (prefers-reduced-motion: reduce) { .acq-note { transition: none; } }

/* ------------------------------------------ ETL -> NASA evidence hand-off ---
   One-time underline sweep on the flagship heading as Selected Work enters
   view — the DOM half of the subtle hand-off (the renderer draws a short cyan
   line down from the last stage). Decorative; never gates content. */
#selected-work .project--flagship h3 { position: relative; }
#selected-work .project--flagship h3::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -6px;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, var(--flow), rgb(177 140 255 / .5) 60%, transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 900ms var(--ease) 200ms;
}
#selected-work[data-in-view] .project--flagship h3::after { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  #selected-work .project--flagship h3::after { transition: none; }
}

.footer-credit {
  flex-basis: 100%;
  color: var(--ink-3);
  font: 400 .64rem/1.5 Mono, monospace;
  letter-spacing: .02em;
}

/* ------------------------------------ mobile: assembly gutter beside labels --
   On the vertical rail each cell reserves a fixed left gutter that only the 3D
   assembly occupies; the label text starts after it. Previously the renderer
   placed each assembly at its label's own centre, so the label always covered
   it. MOBILE_SLOT in orbital-space.js must match this width. */
@media (max-width: 900px) {
  /* The gutter must be a genuine HOLE in the panel, not a padded area inside
     it. The rail carried background rgba(12,12,12,.78) across its whole width
     and the canvas sits at z-index -2, so every assembly rendered at 22 percent
     over black and read as an empty box. The panel now starts after the gutter
     and the gutter itself is open to the scene. */
  /* backdrop-filter on the rail blurs EVERYTHING painted behind it, and the
     scene canvas sits at z-index -2 behind. With the gutter opened up, that
     14px blur was destroying the assemblies into soft blobs - isolated by
     toggling one property at a time: removing it alone took the gutter strip
     from stddev 21.45 to 41.84, matching the rail-hidden reference of 41.34.
     The rail is transparent at this breakpoint, so it has nothing to blur. */
  .etl-rail { background: transparent; border-color: transparent; gap: 0;
    backdrop-filter: none; -webkit-backdrop-filter: none; }
  .etl-rail > li { position: relative; background: transparent; box-shadow: none; }
  .etl-rail > li + li { box-shadow: none; margin-top: 1px; }
  .etl-rail .stage-btn {
    margin-left: var(--mobile-slot);
    min-height: 92px;
    padding-left: var(--s-3);
    background: var(--srf-2);
    border: 1px solid var(--edge);
    border-radius: var(--r-sm);
  }
  .etl-rail > li[data-active] .stage-btn { border-color: rgb(67 217 255 / .45); }
  /* A faint frame so the empty gutter reads as a display region, not a gap.
     ::before is already the progress bar on this breakpoint, so this uses
     ::after (which is only the connector tick on desktop). */
  .etl-rail > li::after {
    content: "";
    position: absolute;
    left: 8px; top: 8px; bottom: 8px;
    width: calc(var(--mobile-slot) - 16px);
    height: auto;
    border: 1px solid var(--edge);
    border-radius: 8px;
    background: linear-gradient(180deg, rgb(255 255 255 / .025), transparent 70%);
    opacity: 0;
    transition: opacity var(--t-mid) var(--ease);
    pointer-events: none;
  }
  [data-stage-engaged] .etl-rail > li::after { opacity: 1; }
}


/* ---------------------------------------------- six pipeline cards, tiers --
   3 x 2 on wide, 2 x 3 on medium, 1 column on narrow. Never 5 + 1. */
@media (max-width: 1100px) {
  .pipeline { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .pipeline { grid-template-columns: minmax(0, 1fr); }
}
