:root {
  --amber: #3ddc8b;
  --amber-deep: #186a41;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* `clip`, not `hidden`. Per spec a non-visible value on one axis forces the
     other to `auto`, so `overflow-x: hidden` here quietly made <body> a scroll
     container: scroll events then fire on body and never reach window, which
     kills every window-level scroll listener on the page — including the
     fallbacks that fill the reveals and the marks when IntersectionObserver
     does not deliver. `clip` blocks the same overflow without creating a
     scroll box. */
  overflow-x: clip;
  font-feature-settings: "tnum" 1, "ss01" 1;
}

h1, h2 { font-weight: 600; letter-spacing: -0.035em; margin: 0; }

/* ---------- atmosphere ---------- */
.bg-glow, .grid-lines, .grain, .vignette {
  position: fixed; inset: 0; pointer-events: none;
}
.bg-glow {
  z-index: 0;
  background:
    radial-gradient(52% 40% at 50% 38%, rgba(61, 220, 139, .06), transparent 72%),
    radial-gradient(90% 60% at 50% 110%, rgba(38, 62, 104, .18), transparent 70%);
}
.grid-lines {
  z-index: 0; opacity: .16;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 80px 80px;
  mask-image: radial-gradient(66% 56% at 50% 42%, #000 30%, transparent 100%);
  -webkit-mask-image: radial-gradient(66% 56% at 50% 42%, #000 30%, transparent 100%);
}
/* fine film grain keeps the large dark areas from banding */
.grain {
  z-index: 45; opacity: .30; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}
.vignette {
  z-index: 44;
  box-shadow: inset 0 0 min(16vw, 190px) rgba(0, 0, 0, .38);
}

/* ---------- chrome ---------- */
.progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px;
  z-index: 50; background: rgba(255, 255, 255, .045);
}
.progress-bar {
  height: 100%; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--amber-deep), var(--amber));
}
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; justify-content: space-between; align-items: center;
  padding: 20px clamp(18px, 3.2vw, 34px);
  font-family: var(--mono); font-size: .62rem;
  letter-spacing: .22em; text-transform: uppercase;
}
.brand { color: var(--fg); font-weight: 500; }
.brand span { color: var(--amber); }
.topbar-meta { color: var(--dim); }
.topbar-meta span { color: var(--faint); margin: 0 .35em; }

/* ---------- intro ---------- */
.intro {
  position: relative; z-index: 2; min-height: 100vh;
  display: grid; place-content: center; text-align: center;
  padding: 6rem 2rem 3rem;
}
.eyebrow {
  font-family: var(--mono); font-size: .65rem;
  letter-spacing: .3em; text-transform: uppercase;
  color: var(--amber); margin-bottom: 1.6rem;
}
.intro :is(h1, .intro-title) {
  font-size: clamp(2.4rem, 7vw, 5rem);
  line-height: 1.02; margin-bottom: 1.6rem;
}
.intro :is(h1, .intro-title) span { color: var(--amber); }
.intro > p {
  max-width: 44ch; margin: 0 auto;
  color: var(--muted); font-size: 1rem; line-height: 1.7;
}

/* stat strip */
.stats {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(1.6rem, 5vw, 4rem);
  margin: 3.4rem auto 0; padding: 1.5rem 0 0;
  border-top: 1px solid var(--line);
  max-width: 700px;
}
.stats div { text-align: center; }
.stats dt {
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--dim); margin-bottom: .5rem;
}
.stats dd {
  margin: 0; font-size: 1.6rem; font-weight: 600; letter-spacing: -.03em;
}
.stats dd em { font-style: normal; color: var(--amber); font-size: .9rem; margin-left: .1em; }

.scroll-cue {
  margin-top: 3.2rem;
  font-family: var(--mono); font-size: .6rem;
  letter-spacing: .3em; text-transform: uppercase; color: var(--dim);
}
.scroll-cue::after {
  content: ""; display: block; width: 1px; height: 44px; margin: 14px auto 0;
  background: linear-gradient(var(--amber), transparent);
  animation: drop 2.4s var(--ease) infinite;
}
@keyframes drop {
  0%, 100% { opacity: .2; transform: scaleY(.4); transform-origin: top; }
  50%      { opacity: 1;  transform: scaleY(1);  transform-origin: top; }
}

/* ---------- stage ---------- */
.stage { position: sticky; top: 0; height: 100vh; width: 100%; z-index: 1; }
#gl { display: block; width: 100%; height: 100%; }
.hud { position: absolute; inset: 0; pointer-events: none; z-index: 3; }

/* side panels */
.panel {
  position: absolute; top: 30%;
  width: min(27vw, 340px);
  transform: translateY(-50%);
  opacity: 0; visibility: hidden;
  transition: opacity .35s var(--ease), visibility .35s;
}
.panel.show { opacity: 1; visibility: visible; }
.panel-l { left: clamp(20px, 4vw, 56px); }
.panel-r { right: clamp(20px, 4vw, 56px); text-align: right; }

/* staggered entrance for the copy */
.panel > * {
  opacity: 0; transform: translateY(10px);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
}
.panel.in > * { opacity: 1; transform: none; }
.panel.in > *:nth-child(1) { transition-delay: .02s }
.panel.in > *:nth-child(2) { transition-delay: .07s }
.panel.in > *:nth-child(3) { transition-delay: .12s }
.panel.in > *:nth-child(4) { transition-delay: .17s }

.tag {
  font-family: var(--mono); font-size: 2.3rem; font-weight: 700;
  color: transparent; -webkit-text-stroke: 1.1px var(--amber-deep);
  line-height: 1; margin-bottom: .55rem;
}
.pname {
  font-size: clamp(1.3rem, 2.2vw, 1.85rem);
  margin-bottom: .5rem; line-height: 1.14;
}
.prole {
  font-family: var(--mono); font-size: .6rem;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--amber); margin-bottom: 1.2rem;
}
.pdesc { color: var(--muted); line-height: 1.78; font-size: .87rem; margin: 0; }

/* spec table */
.spec {
  border-top: 1px solid var(--line);
  padding: .6rem 0;
  display: flex; justify-content: flex-end;
  gap: 1.5rem; align-items: baseline;
}
.spec:last-child { border-bottom: 1px solid var(--line); }
.spec-k {
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--dim); white-space: nowrap;
}
.spec-v { font-size: .85rem; font-weight: 500; letter-spacing: -.012em; }

/* hero + finale cards */
.card {
  position: absolute; left: 50%; top: 7%;
  transform: translateX(-50%) translateY(8px);
  width: min(88vw, 560px); text-align: center;
  opacity: 0; visibility: hidden;
  transition: opacity .6s var(--ease), transform .6s var(--ease), visibility .6s;
}
.card.show { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
.card h2 { font-size: clamp(1.6rem, 3.4vw, 2.5rem); margin-bottom: .9rem; line-height: 1.1; }
.card p { color: var(--muted); line-height: 1.75; font-size: .92rem; margin: 0 auto; max-width: 48ch; }
.card .eyebrow { margin-bottom: 1rem; }

/* build-step caption, shown while the instrument goes back together */
.build {
  position: absolute; left: 50%; top: 8%;
  transform: translateX(-50%) translateY(6px);
  width: min(88vw, 460px); text-align: center;
  opacity: 0; visibility: hidden;
  transition: opacity .4s var(--ease), transform .4s var(--ease), visibility .4s;
}
.build.show { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
.build-n {
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .26em; text-transform: uppercase;
  color: var(--amber); margin-bottom: .7rem;
}
.build h4 {
  font-size: clamp(1.15rem, 2.4vw, 1.6rem); font-weight: 600;
  letter-spacing: -.025em; margin: 0 0 .4rem;
}
.build p { margin: 0; color: var(--muted); font-size: .87rem; line-height: 1.6; }

/* six-condition legend on the array panel */
.legend { margin-top: 1.3rem; }
.legend-h {
  font-family: var(--mono); font-size: .55rem;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--dim); margin-bottom: .6rem;
}
.ch {
  display: flex; align-items: center; gap: .5rem;
  padding: .26rem 0; justify-content: flex-end;
}
.ch-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  box-shadow: 0 0 7px currentColor;
}
.ch.green .ch-dot { background: #4dff7a; color: #4dff7a; }
.ch.red   .ch-dot { background: #ff5f4a; color: #ff5f4a; }
.ch-name {
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); width: 2.6rem; text-align: left;
}
.ch-bar {
  flex: 1; max-width: 74px; height: 3px; border-radius: var(--r-xs);
  background: rgba(255, 255, 255, .09); overflow: hidden;
}
.ch-bar i { display: block; height: 100%; border-radius: var(--r-xs); background: currentColor; }
.ch.green .ch-bar { color: #4dff7a; }
.ch.red   .ch-bar { color: #ff5f4a; }
.ch-val {
  font-family: var(--mono); font-size: .62rem; color: var(--fg);
  width: 4.6rem; text-align: right;
}
.ch-val em { font-style: normal; color: var(--dim); font-size: .82em; margin-left: .18em; }
.legend-f {
  margin-top: .7rem; font-size: .68rem; line-height: 1.5;
  color: var(--dim); text-align: right;
}

/* index counter */
.counter {
  position: absolute; left: 50%; bottom: 46px;
  transform: translateX(-50%);
  font-family: var(--mono); font-size: .68rem; letter-spacing: .14em;
  color: var(--dim); opacity: 0; transition: opacity .35s var(--ease);
}
.counter.show { opacity: 1; }
.counter b { color: var(--amber); font-weight: 600; }
.counter i { color: var(--faint); font-style: normal; margin: 0 .45em; }

/* progress rail */
.rail {
  position: absolute; left: 50%; bottom: 24px;
  transform: translateX(-50%);
  display: flex; gap: 7px; align-items: center;
  opacity: 0; transition: opacity .35s var(--ease);
  /* One dot per part, so the natural width scales with the part count and
     overflowed a phone at 15 parts. Cap it and let the dots shrink instead. */
  max-width: calc(100vw - 32px);
}
.rail.show { opacity: 1; }
.dot {
  width: 20px; flex: 0 1 20px; min-width: 5px;
  height: 2px; border-radius: var(--r-xs);
  background: rgba(255, 255, 255, .13);
  transition: background .4s var(--ease), width .4s var(--ease);
}
.dot.done { background: rgba(61, 220, 139, .32); }
.dot.on { background: var(--amber); width: 34px; flex-basis: 34px; }

/* loader */
.loader {
  position: absolute; inset: 0;
  display: grid; place-content: center; justify-items: center; gap: 12px;
  font-family: var(--mono); font-size: .62rem;
  letter-spacing: .26em; text-transform: uppercase; color: var(--dim);
  transition: opacity .7s var(--ease);
}
.loader b { color: var(--amber); font-weight: 500; letter-spacing: .1em; }
.loader.hide { opacity: 0; pointer-events: none; }

.track { position: relative; z-index: 0; }

/* outro */
.outro {
  position: relative; z-index: 2; min-height: 60vh;
  display: grid; place-content: center; align-content: center; justify-items: center;
  text-align: center; padding: 6rem 2rem; gap: .4rem;
}
.outro-lead {
  max-width: 40ch; margin: 0 auto 1.8rem;
  color: var(--muted); font-size: 1.05rem; line-height: 1.72;
}
.outro-lead strong { color: var(--fg); font-weight: 600; }
.outro-meta {
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .24em; text-transform: uppercase; color: var(--faint);
}

/* ══════════════════ technical record ══════════════════ */
.doc-wrap {
  position: relative; z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 760px) minmax(0, 1fr);
  padding: 0 clamp(18px, 4vw, 48px) 6rem;
  border-top: 1px solid var(--line);
}

/* sticky contents rail */
.doc-nav {
  grid-column: 1;
  position: sticky; top: 0; height: 100vh;
  display: flex; flex-direction: column; justify-content: center;
  padding-right: 2rem;
}
.doc-nav-label {
  font-family: var(--mono); font-size: .55rem;
  letter-spacing: .26em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 1.1rem;
}
.doc-nav ol { list-style: none; margin: 0; padding: 0; }
.doc-nav li { margin-bottom: .7rem; }
.doc-nav a {
  display: flex; gap: .7rem; align-items: baseline;
  text-decoration: none; color: var(--dim);
  font-size: .8rem; line-height: 1.3;
  transition: color .25s var(--ease);
  border-left: 1px solid transparent; padding-left: .8rem;
  margin-left: -.8rem;
}
.doc-nav a b {
  font-family: var(--mono); font-size: .62rem; color: var(--faint);
  transition: color .25s var(--ease);
}
.doc-nav a:hover { color: var(--fg); }
.doc-nav a.on { color: var(--fg); border-left-color: var(--amber); }
.doc-nav a.on b { color: var(--amber); }

.doc { grid-column: 2; padding-top: 5rem; }

/* ---- document header ---- */
.doc-head { margin-bottom: 5rem; }
.doc-head h1 {
  font-size: clamp(2rem, 5vw, 3.4rem);
  line-height: 1.03; margin-bottom: 1.6rem;
}
.standfirst {
  font-size: 1.1rem; line-height: 1.62; color: var(--fg);
  margin: 0 0 1.4rem; font-weight: 350;
}
.doc-aim {
  color: var(--muted); line-height: 1.75; font-size: .95rem;
  margin: 0 0 2rem; padding-left: 1.1rem;
  border-left: 2px solid var(--line);
}
.status {
  display: flex; align-items: flex-start; gap: .7rem;
  font-size: .82rem; line-height: 1.6; color: var(--muted);
  background: rgba(61, 220, 139, .05);
  border: 1px solid rgba(61, 220, 139, .16);
  border-radius: var(--r-xs); padding: .85rem 1rem;
}
.status-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--amber); flex: none; margin-top: .5rem;
}

/* ---- part dividers ---- */
.part {
  margin: 7rem 0 3rem; padding-top: 2.2rem;
  border-top: 1px solid var(--line);
}
.part:first-of-type { margin-top: 0; }
.part-mark {
  display: flex; align-items: baseline; gap: .6rem; margin-bottom: .7rem;
}
.part-mark span {
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .26em; text-transform: uppercase; color: var(--faint);
}
.part-mark b {
  font-family: var(--mono); font-size: 1.1rem; color: var(--amber); font-weight: 600;
}
.part h2 { font-size: clamp(1.6rem, 3.4vw, 2.4rem); line-height: 1.08; }

/* ---- sections ---- */
.sec { margin-bottom: 3.4rem; }
.sec h3 {
  font-size: 1.42rem; font-weight: 600; letter-spacing: -.02em;
  margin: 0 0 1.1rem; line-height: 1.3;
  display: flex; gap: .75rem; align-items: baseline;
}
.sec h3 i, .sec h4 i {
  font-family: var(--mono); font-style: normal;
  font-size: .72em; color: var(--amber); font-weight: 500;
  flex: none;
}
.sec h3 em, .sec h4 em { font-style: normal; color: var(--dim); font-weight: 400; }
.sec h4 {
  font-size: 1.1rem; font-weight: 600; margin: 2.2rem 0 .8rem;
  display: flex; gap: .7rem; align-items: baseline;
}
.sec h5 { font-size: .87rem; font-weight: 600; margin: 0 0 .4rem; }
.sec p {
  /* Body was .95rem/68ch, which measures 15.2px at 70 characters — small for
     long-form and at the top of the readable range. 1.06rem is about 17px, and
     because the cap is in ch it has to come down with it or the measure just
     stays where it was: 64ch lands near the 66-character optimum. */
  color: var(--muted); line-height: 1.8; font-size: 1.05rem;
  margin: 0 0 1.25rem; max-width: 64ch;
}
.sec p b, .sec li b { color: var(--fg); font-weight: 600; }
.sec li { font-size: 1.05rem; line-height: 1.8; }
.sec a { color: var(--amber); text-decoration: none; border-bottom: 1px solid rgba(61,220,139,.3); }
.sec a:hover { border-bottom-color: var(--amber); }
.sec abbr { text-decoration: none; border-bottom: 1px dotted var(--dim); cursor: help; }
.lead-note {
  font-size: 1.02rem !important; color: var(--fg) !important;
  border-left: 2px solid var(--amber); padding-left: 1.1rem;
}
.fineprint { font-size: .85rem !important; color: var(--dim) !important; }

/* ---- pending value chip ---- */
.pending {
  display: inline-block; vertical-align: baseline;
  min-width: 4.4em; height: 1.05em;
  border: 1px dashed rgba(61, 220, 139, .42);
  border-radius: var(--r-xs);
  background: repeating-linear-gradient(-45deg,
    rgba(61,220,139,.05) 0 4px, transparent 4px 8px);
}
.pending.s { min-width: 2.4em; }
.pending.eq { min-width: 12em; height: 1.5em; }

/* ---- open item ---- */
.openitem {
  display: flex; gap: .9rem; align-items: flex-start;
  border: 1px solid rgba(255,255,255,.08);
  border-left: 2px solid var(--amber-deep);
  border-radius: var(--r-xs); padding: .9rem 1.1rem;
  margin: 1.4rem 0; background: rgba(255,255,255,.017);
}
.openitem.tight { margin: .9rem 0 0; padding: .7rem .9rem; }
.openitem-tag {
  font-family: var(--mono); font-size: .55rem;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--amber); flex: none; margin-top: .28rem;
}
.openitem p, .openitem ul { margin: 0; font-size: .85rem !important; line-height: 1.65; }
.openitem ul { padding-left: 1.1rem; color: var(--muted); }
.openitem li { margin-bottom: .3rem; font-size: .85rem; line-height: 1.6; }

/* ---- blank slot ---- */
.blank-slot {
  border: 1px dashed rgba(255,255,255,.11);
  border-radius: var(--r-sm); min-height: 130px;
  display: grid; place-content: center;
  margin: 1.2rem 0;
  background: repeating-linear-gradient(-45deg,
    rgba(255,255,255,.012) 0 8px, transparent 8px 16px);
}
.blank-slot::after {
  content: attr(data-label) " — to be written";
  font-family: var(--mono); font-size: .6rem;
  letter-spacing: .2em; text-transform: uppercase; color: var(--faint);
}

/* ---- keynote ---- */
.keynote {
  display: flex; gap: 1.6rem; align-items: center;
  margin: 2rem 0; padding: 1.4rem 1.6rem;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: linear-gradient(100deg, rgba(61,220,139,.06), transparent 60%);
}
.keynote-fig {
  font-size: 2.6rem; font-weight: 650; letter-spacing: -.04em;
  color: var(--amber); line-height: 1; flex: none;
}
/* The unit suffix rides on the keynote's dark panel, so it cannot use the
   deep variant — that is tuned for white and lands near 2.9:1 here. Use
   --amber: the light theme already promotes it to --amber-deep. */
.keynote-fig em { font-style: normal; font-size: .38em; margin-left: .12em; color: var(--amber); }
.keynote p { margin: 0 !important; font-size: .9rem !important; }

/* ---- tables ---- */
.table-scroll { overflow-x: auto; margin: 1.6rem 0; }
table { border-collapse: collapse; width: 100%; font-size: .84rem; min-width: 560px; }
table caption {
  text-align: left; font-family: var(--mono); font-size: .55rem;
  letter-spacing: .22em; text-transform: uppercase; color: var(--faint);
  padding-bottom: .7rem;
}
table th {
  text-align: left; font-family: var(--mono); font-size: .56rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--dim);
  font-weight: 500; padding: .6rem .8rem; border-bottom: 1px solid var(--line);
}
table td {
  padding: .72rem .8rem; border-bottom: 1px solid rgba(255,255,255,.05);
  color: var(--muted); line-height: 1.5; vertical-align: top;
}
table tbody tr:hover td { background: rgba(255,255,255,.017); }
table td:first-child { color: var(--fg); font-weight: 500; }
table .num { text-align: right; white-space: nowrap; }
table tfoot td {
  border-bottom: none; border-top: 1px solid var(--line);
  color: var(--fg); font-weight: 600; padding-top: .9rem;
}
.compare tr.ours td { background: rgba(61,220,139,.05); }
.compare tr.ours td:first-child { color: var(--amber); }

/* ---- spec card ---- */
.spec-card {
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 1.3rem 1.5rem; margin: 1.8rem 0;
}
.spec-card-title {
  font-family: var(--mono); font-size: .56rem;
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--amber); margin-bottom: 1rem;
}
.spec-card dl {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: .9rem 1.6rem; margin: 0 0 1rem;
}
.spec-card dt {
  font-family: var(--mono); font-size: .55rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--dim);
  margin-bottom: .25rem;
}
.spec-card dd { margin: 0; font-size: .87rem; font-weight: 500; }
.spec-note { font-size: .84rem !important; color: var(--dim) !important; margin: 0 !important; }

/* ---- iterations ---- */
.iters { list-style: none; margin: 2rem 0; padding: 0; }
.iters li { display: flex; gap: 1.4rem; padding-bottom: 2.2rem; position: relative; }
.iters li::before {
  content: ""; position: absolute; left: 17px; top: 40px; bottom: 0;
  width: 1px; background: var(--line);
}
.iters li:last-child::before { display: none; }
.iter-n {
  font-family: var(--mono); font-size: .68rem; font-weight: 600;
  color: var(--amber); flex: none;
  width: 35px; height: 35px; border-radius: 50%;
  border: 1px solid rgba(61,220,139,.3);
  display: grid; place-content: center;
  background: var(--bg); position: relative; z-index: 1;
}
.iter-body { flex: 1; min-width: 0; }
.iter-body h4 { margin: .35rem 0 .6rem; font-size: 1rem; }
.iter-cause { font-size: .87rem !important; color: var(--dim) !important; }

/* delta */
.delta {
  display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 1rem 1.2rem; margin: 1.1rem 0;
}
.delta > div { text-align: center; }
.delta span {
  display: block; font-family: var(--mono); font-size: .52rem;
  letter-spacing: .18em; text-transform: uppercase; color: var(--faint);
  margin-bottom: .25rem;
}
.delta b { font-size: 1.5rem; font-weight: 650; letter-spacing: -.03em; color: var(--muted); }
.delta b.good { color: var(--amber); }
.delta-arrow { color: var(--faint); font-size: 1.1rem; }
.delta p {
  flex: 1; min-width: 190px; margin: 0 !important;
  font-size: .78rem !important; color: var(--dim) !important; line-height: 1.55;
}

/* ---- callout ---- */
.callout {
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 1.2rem 1.4rem; margin: 2rem 0;
  background: rgba(255,255,255,.017);
}
.callout h5 { color: var(--fg); font-size: .92rem; margin-bottom: .5rem; }
.callout h5 em { font-style: italic; color: var(--amber); }
.callout p { margin: 0 !important; font-size: .89rem !important; }
.callout.warn { border-color: rgba(61,220,139,.22); background: rgba(61,220,139,.045); }

/* ---- filter steps ---- */
.filter-steps {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden;
  margin: 1.6rem 0;
}
.filter-steps > div { background: var(--bg); padding: 1rem; }
.filter-steps b {
  display: block; font-family: var(--mono); font-size: .62rem;
  color: var(--amber); margin-bottom: .5rem;
}
.filter-steps p { margin: 0 !important; font-size: .82rem !important; line-height: 1.55; }

/* ---- protocol ---- */
.protocol { counter-reset: p; list-style: none; margin: 1.4rem 0; padding: 0; }
.protocol li {
  counter-increment: p; position: relative;
  padding-left: 2.4rem; margin-bottom: 1.5rem;
}
.protocol li::before {
  content: counter(p); position: absolute; left: 0; top: 0;
  font-family: var(--mono); font-size: .62rem; color: var(--amber);
  width: 1.5rem; height: 1.5rem; border-radius: 50%;
  border: 1px solid rgba(61,220,139,.28);
  display: grid; place-content: center;
}
.protocol p { margin: 0 !important; font-size: .9rem !important; }

/* ---- equation ---- */
.equation {
  display: flex; align-items: center; gap: .9rem; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 1.3rem 1.5rem; margin: 1.4rem 0;
  background: rgba(255,255,255,.017);
  font-family: var(--mono);
}
.eq-lhs { font-size: 1.05rem; color: var(--fg); }
.eq-eq { color: var(--dim); }
.eq-range { font-size: .85rem !important; color: var(--dim) !important; }

/* ---- metrics ---- */
.metrics { display: flex; gap: 2.4rem; flex-wrap: wrap; margin: 1.2rem 0 1.4rem; }
.metrics > div { display: flex; align-items: baseline; gap: .55rem; }
.metrics span {
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--dim);
}
.metrics b { font-size: 1.15rem; font-weight: 600; }
.metrics em { font-style: normal; font-size: .72rem; color: var(--faint); }

/* ---- figures ---- */
.fig { margin: 2rem 0; }
.fig-slot {
  border: 1px dashed rgba(255,255,255,.11); border-radius: var(--r-sm);
  min-height: 230px; display: grid; place-content: center;
  background: repeating-linear-gradient(-45deg,
    rgba(255,255,255,.012) 0 8px, transparent 8px 16px);
}
.fig-slot span {
  font-family: var(--mono); font-size: .6rem;
  letter-spacing: .2em; text-transform: uppercase; color: var(--faint);
}
.fig figcaption {
  font-size: .82rem; color: var(--dim); line-height: 1.6;
  padding-top: .8rem; max-width: 62ch;
}

/* ---- flow path ---- */
.flow { color: var(--fg); font-weight: 500; white-space: nowrap; }
.flow i { color: var(--amber); font-style: normal; margin: 0 .18em; }

/* ---- parameters ---- */
.params { display: grid; gap: 1rem; margin: 1.6rem 0; }
.param {
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 1.2rem 1.4rem;
}
.param.prio { border-color: rgba(61,220,139,.24); background: rgba(61,220,139,.035); }
.param-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-bottom: .7rem; flex-wrap: wrap;
}
.param-head h4 { margin: 0; font-size: 1rem; }
.tag {
  font-family: var(--mono); font-size: .52rem;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--dim); border: 1px solid var(--line);
  border-radius: var(--r-xs); padding: .22rem .5rem;
  /* `flex: none` here used to let a long tag ("Highest priority", widened by the
     .18em tracking) push past the page edge on a phone. Shrinkable, and allowed
     to wrap, so it can never be the widest thing on the page. */
  flex: 0 1 auto; max-width: 100%;
}
.tag.hot { color: var(--amber); border-color: rgba(61,220,139,.32); }
.param p { margin: 0 0 .7rem !important; font-size: .89rem !important; }
.param-note { color: var(--dim) !important; font-size: .84rem !important; }

/* ---- headline stats ---- */
.headline-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden;
  margin: 1.8rem 0;
}
.headline-stats > div { background: var(--bg); padding: 1.2rem 1rem; text-align: center; }
.headline-stats b {
  display: block; font-size: 1.7rem; font-weight: 650;
  letter-spacing: -.04em; color: var(--amber); line-height: 1;
}
.headline-stats b em { font-style: normal; font-size: .45em; margin-left: .06em; }
.headline-stats span {
  display: block; margin-top: .5rem;
  font-family: var(--mono); font-size: .52rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--dim);
}

/* ---- phases ---- */
.phases {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden;
  margin: 1.6rem 0;
}
.phases > div { background: var(--bg); padding: .9rem 1rem; }
.phases span {
  display: block; font-family: var(--mono); font-size: .55rem;
  letter-spacing: .14em; color: var(--amber); margin-bottom: .35rem;
}
.phases b { font-size: .85rem; font-weight: 500; color: var(--muted); }

/* ---- limits ---- */
.limits { display: grid; gap: 1.4rem; margin: 1.4rem 0 1.6rem; }
.limits > div { padding-left: 1.1rem; border-left: 2px solid var(--line); }
.limits h4 { margin: 0 0 .45rem; font-size: .95rem; }
.limits p { margin: 0 !important; font-size: .89rem !important; }

/* ---- pull quote ---- */
.pull {
  margin: 2rem 0; padding: 1.6rem 0;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  font-size: clamp(1.05rem, 2vw, 1.35rem); line-height: 1.5;
  font-weight: 350; color: var(--fg); letter-spacing: -.015em;
}
.pull b { color: var(--amber); font-weight: 650; }

.doc-foot { margin-top: 5rem; padding-top: 2rem; border-top: 1px solid var(--line); }

/* ---- condition matrix ---- */
.matrix {
  display: grid;
  grid-template-columns: auto repeat(3, 1fr);
  gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden;
  margin: 1.8rem 0;
}
.matrix > div { background: var(--bg); padding: .75rem .9rem; }
.mx-corner { background: var(--bg); }
.mx-h {
  font-family: var(--mono); font-size: .55rem;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--dim); text-align: center;
}
.mx-w {
  display: flex; align-items: center; gap: .5rem;
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .12em; color: var(--muted); white-space: nowrap;
}
.mx-w span { width: 7px; height: 7px; border-radius: 50%; box-shadow: 0 0 8px currentColor; }
.mx-w.green span { background: #4dff7a; color: #4dff7a; }
.mx-w.red span { background: #ff5f4a; color: #ff5f4a; }
.mx-c { text-align: center; }
.mx-dots { display: flex; gap: 4px; justify-content: center; margin-bottom: .4rem; }
.mx-dots i { width: 7px; height: 7px; border-radius: 50%; display: block; }
.mx-c.green .mx-dots i { background: #4dff7a; }
.mx-c.red .mx-dots i { background: #ff5f4a; }
.mx-c.low .mx-dots i { opacity: .28 }
.mx-c.mid .mx-dots i { opacity: .60 }
.mx-c.high .mx-dots i { opacity: 1; box-shadow: 0 0 8px currentColor; }
.mx-c.green.high .mx-dots i { color: #4dff7a }
.mx-c.red.high .mx-dots i { color: #ff5f4a }
.mx-v { font-family: var(--mono); font-size: .68rem; color: var(--fg); }
.mx-v em { font-style: normal; color: var(--dim); font-size: .8em; margin-left: .2em; }
.mx-note {
  grid-column: 1 / -1; text-align: center;
  font-size: .68rem; color: var(--dim);
}

/* ---- I² chart ---- */
#i2-chart { display: grid; gap: 1.4rem; }
.i2-panel {
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 1rem 1.1rem .4rem;
}
.i2-h {
  display: flex; align-items: center; gap: .55rem;
  font-family: var(--mono); font-size: .6rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
  margin-bottom: .5rem;
}
.i2-sw { width: 8px; height: 8px; border-radius: 50%; box-shadow: 0 0 8px currentColor; }
.i2-panel.green .i2-sw { background: #4dff7a; color: #4dff7a; }
.i2-panel.red .i2-sw { background: #ff5f4a; color: #ff5f4a; }
.i2-h b { margin-left: auto; color: var(--fg); font-weight: 600; }
.i2-h i { font-style: normal; color: var(--faint); }
svg.i2 { width: 100%; height: auto; display: block; overflow: visible; }
.i2-ax { stroke: rgba(255, 255, 255, .12); stroke-width: 1; }
.i2-tick { fill: var(--dim); font-family: var(--mono); font-size: 9px; text-anchor: middle; }
.i2-unit { fill: var(--faint); font-family: var(--mono); font-size: 8px; text-anchor: end; }
.i2-band { fill: rgba(255, 255, 255, .035); stroke: rgba(255, 255, 255, .07); }
.i2-band-l {
  font-family: var(--mono); font-size: 8.5px; text-anchor: middle;
  letter-spacing: .12em; text-transform: uppercase; fill: var(--dim);
}
.i2-dot.rej { fill: rgba(255, 255, 255, .14); }
.i2-panel.green .i2-dot.sel { fill: #4dff7a; }
.i2-panel.red .i2-dot.sel { fill: #ff5f4a; }
.i2-dot.sel.t0 { opacity: .42 }
.i2-dot.sel.t1 { opacity: .72 }
.i2-dot.sel.t2 { opacity: 1 }

/* misc */
.swatch {
  display: inline-block; width: 9px; height: 9px; border-radius: var(--r-xs);
  margin-right: .5rem; vertical-align: -1px;
  border: 1px solid rgba(255, 255, 255, .16);
}
.swatch.black { background: #16181b }
.swatch.grey { background: #6a6f77 }
.swatch.white { background: #d9dbdd }
ul.tight { margin: .4rem 0 .9rem; padding-left: 1.1rem; color: var(--muted); }
ul.tight li { font-size: .9rem; line-height: 1.7; margin-bottom: .2rem; }

/* ---------- mobile ---------- */
@media (max-width: 1100px) {
  /* Two separate traps here, both of which blew the page out to 560px wide on a
     390px phone — the width of the tables' `min-width` — dragging every fixed
     layer (topbar, progress bar, glow) out with it.

     1. A bare `1fr` is `minmax(auto, 1fr)`, and that `auto` minimum is
        min-content, which the tables set. The track must be `minmax(0, …)`.
     2. `margin: 0 auto` on a grid item makes it shrink-to-fit rather than
        stretch, and shrink-to-fit floors at min-content — so the item stayed
        560px even once the track was correct. The track now carries both the
        max-width and the centring, so the item can just stretch into it. */
  .doc-wrap { grid-template-columns: minmax(0, 760px); justify-content: center; }
  .doc-nav { display: none; }
  .doc { grid-column: 1; min-width: 0; }
}

@media (max-width: 900px) {
  .topbar { font-size: .55rem; padding: 14px 16px; }
  .topbar-meta { display: none; }
  .panel {
    width: calc(100% - 32px);
    left: 16px; right: 16px; transform: none; text-align: left;
  }
  .panel-l { top: 6%; }
  .panel-r { top: 26%; text-align: left; }
  .spec { justify-content: flex-start; }
  .tag { font-size: 1.8rem; }
  .pdesc { font-size: .82rem; }
  .card { top: 7%; }
  .stats { gap: 1.4rem 2rem; }
  .stats dd { font-size: 1.3rem; }
  .counter { bottom: 40px; }

  .doc-wrap { padding-bottom: 4rem; }
  .doc { padding-top: 3rem; }
  .part { margin: 4.5rem 0 2.2rem; }
  .sec p, .sec li { font-size: 1rem; }
  .keynote { flex-direction: column; align-items: flex-start; gap: .9rem; }
  .iters li { gap: 1rem; }
  .iters li::before { left: 15px; }
  .iter-n { width: 31px; height: 31px; font-size: .62rem; }
  .metrics { gap: 1.4rem; }
  .headline-stats b { font-size: 1.4rem; }
  .doc-head h1 { font-size: clamp(1.7rem, 8vw, 2.4rem); }
  .standfirst { font-size: 1rem; }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue::after { animation: none; }
  .panel > * { transition: none; opacity: 1; transform: none; }
}

/* ---- photo frames ---- */
.frames {
  display: grid; gap: 1rem;
  /* capped, not 1fr — a lone portrait frame stretched to the full column runs
     most of a screen tall */
  grid-template-columns: repeat(auto-fit, minmax(220px, 330px));
  justify-content: start;
  margin: 1.6rem 0;
}
.frame { margin: 1.6rem 0; }
.frames .frame { margin: 0; }
.frame-img {
  position: relative; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: #0b0d10;
  /* the real photos are portrait phone shots, so portrait is the default —
     cropping them into a landscape box throws most of the device away */
  aspect-ratio: 3 / 4;
}
.frame-img img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: saturate(.92) contrast(1.04);
  object-position: center 45%;
}
.frame.land .frame-img { aspect-ratio: 4 / 3; }
.frame.wide .frame-img { aspect-ratio: 16 / 9; }
.frame.square .frame-img { aspect-ratio: 1 / 1; }
/* a single feature photo should not run the full column height */
.frame.hero { max-width: 430px; margin-left: auto; margin-right: auto; }

/* empty state — a labelled slot, so a gap reads as deliberate */
.frame.empty .frame-img {
  border-style: dashed; border-color: rgba(255,255,255,.11);
  background: repeating-linear-gradient(-45deg,
    rgba(255,255,255,.012) 0 8px, transparent 8px 16px);
  display: grid; place-content: center; text-align: center; padding: 1rem;
}
.frame.empty .frame-img::after {
  content: attr(data-label);
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--faint); line-height: 1.9; max-width: 26ch;
}
.frame figcaption {
  padding-top: .65rem; font-size: .78rem; line-height: 1.6; color: var(--dim);
}
.frame figcaption b {
  color: var(--muted); font-weight: 600; font-family: var(--mono);
  font-size: .62rem; letter-spacing: .16em; text-transform: uppercase;
  margin-right: .5rem;
}
/* a frame sitting inside an iteration entry */
.iter-body .frames { margin: 1.1rem 0 .2rem; }
.iter-body .frame figcaption { font-size: .72rem; }

/* upload reminder for iGEM */
.frame-note {
  font-family: var(--mono); font-size: .55rem;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--faint); margin-top: .3rem;
}

/* ---- back to the hardware hub ---- */
.brand.back {
  display: inline-flex; align-items: center; gap: .55rem;
  text-decoration: none; transition: color .3s var(--ease);
}
.brand.back i {
  font-style: normal; color: var(--amber);
  transition: transform .3s var(--ease);
}
.brand.back:hover i { transform: translateX(-3px); }
.topbar-meta a { color: inherit; text-decoration: none; }
.topbar-meta a:hover { color: var(--muted); }

/* ═══════════ elevation pass ═══════════ */

/* deeper base + a display type scale that commits */
h1 { letter-spacing: -.045em; }
h2 { letter-spacing: -.038em; }
::selection { background: color-mix(in srgb, var(--amber) 30%, transparent); }

/* page hand-off, matching the hub. Exit only — see hub.css. */
body.leaving { opacity: 0; transition: opacity .32s var(--ease); }

/* the hero title gets real presence */
.intro :is(h1, .intro-title) { font-size: clamp(2.7rem, 8.4vw, 6rem); line-height: .96; }
.intro :is(h1, .intro-title) span { filter: drop-shadow(0 0 26px color-mix(in srgb, var(--amber) 22%, transparent)); }

/* rules either side of the eyebrow, so it sits rather than floats */
.intro .eyebrow, .doc-head .eyebrow {
  display: flex; align-items: center; gap: .8rem; justify-content: center;
}
.doc-head .eyebrow { justify-content: flex-start; }
.intro .eyebrow::before, .intro .eyebrow::after {
  content: ""; height: 1px; width: clamp(18px, 4vw, 44px);
  background: linear-gradient(90deg, transparent, var(--line-2));
}
.intro .eyebrow::after { background: linear-gradient(90deg, var(--line-2), transparent); }

/* topbar hairline appears once you leave the hero */
.topbar::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-2) 20%, var(--line-2) 80%, transparent);
  opacity: 0; transition: opacity .5s var(--ease);
}
.topbar.stuck::after { opacity: 1; }

/* surfaces become objects: gradient hairline + layered shadow */
.spec-card, .callout, .param, .openitem, .i2-panel, .keynote, .equation, .frame-img {
  position: relative;
  background: linear-gradient(180deg, rgba(255,255,255,.026), rgba(255,255,255,.006));
  box-shadow: 0 1px 0 rgba(255,255,255,.035) inset, 0 16px 34px -28px rgba(0,0,0,.9);
}
.spec-card, .callout, .param, .i2-panel, .keynote { border-radius: var(--r-lg); }

/* stat strip: bigger figures, tighter */
.stats dd { font-size: clamp(1.5rem, 2.5vw, 1.95rem); letter-spacing: -.04em; }
.stats dd em { font-size: .55em; }

/* the part number in the HUD reads as a plate marking */
.tag { -webkit-text-stroke: 1.2px var(--amber-deep); opacity: .95; }

/* headline figures glow faintly, like the LEDs they describe */
.headline-stats b, .keynote-fig {
  text-shadow: 0 0 26px color-mix(in srgb, var(--amber) 26%, transparent);
}

/* photo frames sit on the page instead of floating on it */
.frame-img { border-radius: var(--r-md); overflow: hidden; }
.frame img { transition: transform .8s var(--ease-out), filter .6s var(--ease); }
.frame:hover img { transform: scale(1.035); filter: saturate(1) contrast(1.06); }

/* contents rail: a travelling marker rather than a static tick */
.doc-nav a { position: relative; }
.doc-nav a::before {
  content: ""; position: absolute; left: -.8rem; top: 50%;
  width: 2px; height: 0; border-radius: var(--r-xs); background: var(--amber);
  transform: translateY(-50%);
  transition: height .45s var(--ease-out);
}
.doc-nav a.on::before { height: 1.1rem; }
.doc-nav a.on { border-left-color: transparent; }

/* tables breathe */
table tbody tr { transition: background .3s var(--ease); }

/* a hairline under every part divider */
.part { position: relative; }
.part::after {
  content: ""; position: absolute; left: 0; top: -1px; width: 84px; height: 1px;
  background: linear-gradient(90deg, var(--amber), transparent);
}

/* scrollbar, because it is on screen the whole time */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.09); border-radius: var(--r-md);
  border: 3px solid transparent; background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.18); background-clip: content-box; }

@media (prefers-reduced-motion: reduce) {
  .frame:hover img { transform: none; }
}


/* ---- figure & table numbering ---------------------------------------- */
/* Numbers come from js/figures.js, in document order. The rule above the
   caption is what makes a figure read as a figure rather than a stray image. */
.frame figcaption {
  border-top: 1px solid var(--line);
  margin-top: .55rem;
}
.fignum {
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .17em; text-transform: uppercase;
  color: var(--amber); font-weight: 600;
  margin-right: .1rem;
}
.fignum::after { content: "."; }
table caption .fignum { color: var(--amber); }

/* a cross-reference in the prose: "as ⟨Figure 4⟩ shows" */
a.xref {
  color: var(--amber); text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--amber) 34%, transparent);
}
a.xref:hover { border-bottom-color: var(--amber); }
/* a reference whose target vanished should be loud in review, not silent */
a.xref-broken { color: #ff5f56; }
a.xref-broken::after { content: "[missing figure]"; }

/* ---- lightbox -------------------------------------------------------- */
.zoomable { cursor: zoom-in; }
.zoomable:focus-visible {
  outline: 2px solid var(--amber); outline-offset: 3px;
}
/* an affordance, so it is discoverable without hovering everything */
.zoomable::after {
  content: ""; position: absolute; right: .5rem; bottom: .5rem;
  width: 26px; height: 26px; border-radius: var(--r-xs);
  background: rgba(8,9,11,.66) url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' \
stroke='white' stroke-width='2' stroke-linecap='round'>\
<circle cx='11' cy='11' r='7'/><path d='M20 20l-4-4M11 8v6M8 11h6'/></svg>") center/15px no-repeat;
  opacity: 0; transition: opacity .25s var(--ease);
  pointer-events: none;
}
.zoomable:hover::after, .zoomable:focus-visible::after { opacity: 1; }

.lightbox {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  padding: clamp(16px, 4vw, 54px);
  background: rgba(6,7,9,.93);
  backdrop-filter: blur(7px);
  opacity: 0; transition: opacity .22s var(--ease);
  cursor: zoom-out;
}
.lightbox.open { opacity: 1; }
.lb-fig {
  margin: 0; max-width: min(1100px, 100%); max-height: 100%;
  display: flex; flex-direction: column; gap: .8rem;
  transform: scale(.985); transition: transform .22s var(--ease);
}
.lightbox.open .lb-fig { transform: none; }
.lb-fig img {
  min-height: 0; max-height: 78vh; width: auto; max-width: 100%;
  object-fit: contain; margin: 0 auto; display: block;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  cursor: default;
}
.lb-fig figcaption {
  font-size: .8rem; line-height: 1.6; color: var(--dim);
  max-width: 70ch; margin: 0 auto; text-align: center;
  border-top: 1px solid var(--line); padding-top: .6rem;
}
.lb-close {
  position: absolute; top: 14px; right: 18px;
  width: 40px; height: 40px; border-radius: 50%;
  background: rgba(255,255,255,.07); border: 1px solid var(--line);
  color: var(--muted); font-size: 1.5rem; line-height: 1;
  cursor: pointer; transition: background .2s var(--ease), color .2s var(--ease);
}
.lb-close:hover { background: rgba(255,255,255,.14); color: var(--fg); }

@media (prefers-reduced-motion: reduce) {
  .lightbox, .lb-fig { transition: none; }
}


/* ---- per-part CAD download ------------------------------------------- */
/* Sits under the spec list in the walkthrough. Only printed parts carry a
   `cad` path in parts.js — a bought-in LED's mesh is a stand-in, not something
   anyone should fabricate from. */
.cad-dl {
  display: inline-flex; align-items: center; gap: .5rem;
  margin-top: 1rem; padding: .5rem .8rem;
  font-family: var(--mono); font-size: .58rem;
  letter-spacing: .17em; text-transform: uppercase;
  color: var(--muted); text-decoration: none;
  border: 1px solid var(--line); border-radius: var(--r-xs);
  background: rgba(255,255,255,.02);
  pointer-events: auto;      /* the HUD above it is click-through */
  transition: color .25s var(--ease), border-color .25s var(--ease),
              background .25s var(--ease);
}
.cad-dl:hover, .cad-dl:focus-visible {
  color: var(--amber);
  border-color: color-mix(in srgb, var(--amber) 40%, transparent);
  background: color-mix(in srgb, var(--amber) 7%, transparent);
}
.cad-dl-i {
  width: 11px; height: 11px; flex: none;
  border-bottom: 1.5px solid currentColor;
  position: relative;
}
.cad-dl-i::before {
  content: ""; position: absolute; left: 50%; top: -1px;
  width: 1.5px; height: 7px; background: currentColor; transform: translateX(-50%);
}
.cad-dl-i::after {
  content: ""; position: absolute; left: 50%; top: 3px;
  width: 5px; height: 5px; border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateX(-50%) rotate(45deg);
}


/* ---- section map ------------------------------------------------------ */
/* Built by js/toc.js from the document's own parts. Doubles as the table of
   contents below 1100px, where the sticky rail is hidden. */
.doc-map {
  display: grid; gap: .8rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  margin: 0 0 4.5rem;
}
.map-card {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "n t" ". s";
  column-gap: .75rem; row-gap: .5rem;
  padding: 1.05rem 1.1rem 1.15rem;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: rgba(255,255,255,.015);
  text-decoration: none; color: inherit;
  transition: border-color .3s var(--ease), background .3s var(--ease),
              transform .3s var(--ease);
}
.map-card:hover, .map-card:focus-visible {
  border-color: color-mix(in srgb, var(--amber) 34%, transparent);
  background: color-mix(in srgb, var(--amber) 4%, transparent);
  transform: translateY(-2px);
}
.map-n {
  grid-area: n;
  font-family: var(--mono); font-size: .6rem; letter-spacing: .14em;
  color: var(--amber); padding-top: .2em;
}
.map-t {
  grid-area: t;
  font-size: .92rem; font-weight: 600; line-height: 1.3;
  letter-spacing: -.012em;
}
.map-sub {
  grid-area: s;
  display: flex; flex-direction: column; gap: .28rem;
}
.map-sub > span {
  font-size: .72rem; line-height: 1.45; color: var(--dim);
  padding-left: .72rem; position: relative;
}
.map-sub > span::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 3px; height: 1px; background: var(--faint);
}
.map-more { color: var(--faint) !important; font-family: var(--mono);
            font-size: .6rem !important; letter-spacing: .1em; }

@media (prefers-reduced-motion: reduce) {
  .map-card { transition: none; }
  .map-card:hover, .map-card:focus-visible { transform: none; }
}


/* ---- heading levels ---------------------------------------------------
   These headings were h4/h5 sitting directly under an h2/h3, which skips a
   level and reads as a broken outline to a screen reader. They are promoted
   in the markup and aliased back to their original size here, so the outline
   is correct without the page changing. */
.callout h4 { color: var(--fg); font-size: .92rem; margin-bottom: .5rem; font-weight: 600; }
.callout h4 em { font-style: italic; color: var(--amber); }
.sec h3.minor {
  font-size: .95rem; font-weight: 600; margin: 2.2rem 0 .8rem;
  display: flex; gap: .7rem; align-items: baseline;
  letter-spacing: normal;
}
.iter-body h3.minor { margin: .35rem 0 .6rem; font-size: 1rem; display: block; }


/* ---- skip link & legal footer ----------------------------------------- */
/* Off-screen until focused, so a keyboard user's first Tab reaches the
   content rather than walking the whole navigation. */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  padding: .7rem 1.1rem;
  font-family: var(--mono); font-size: .62rem;
  letter-spacing: .16em; text-transform: uppercase;
  background: var(--bg); color: var(--amber);
  border: 1px solid var(--amber); border-radius: 0 0 4px 0;
  text-decoration: none;
}
.skip-link:focus { left: 0; }

.legal {
  margin-top: 1.4rem; padding-top: 1.2rem;
  border-top: 1px solid var(--line);
  font-size: .72rem; line-height: 1.7; color: var(--faint);
  max-width: 70ch;
}
.legal p { margin: 0 0 .3rem; }
.legal a { color: var(--dim); }
.legal a:hover { color: var(--amber); }

/* ---- condition picker ---- */
/* The matrix and the I² chart were two figures that never referred to each
   other. Selecting a condition picks out the four LEDs that went into it. */
.mx-c { cursor: pointer; transition: background .2s ease; }
.mx-c:hover { background: rgba(255,255,255,.04); }
.mx-c.picked { background: rgba(61,220,139,.10); box-shadow: inset 0 0 0 1px rgba(61,220,139,.45); }
.mx-hint {
  display: block; margin-top: .3rem;
  font-family: var(--mono); font-size: .52rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--faint);
}
#i2-chart.focused .i2-dot { opacity: .16; transition: opacity .25s ease; }
#i2-chart.focused .i2-dot.lit { opacity: 1; r: 6.5; }
body.doc-light .mx-c:hover { background: rgba(15,19,25,.04); }
body.doc-light .mx-c.picked { background: rgba(18,112,63,.09); box-shadow: inset 0 0 0 1px rgba(18,112,63,.4); }


/* A passage describing a procedure that has not been run yet. Marked so a
   reader can never mistake a planned method for a reported result — the page
   used to narrate this calibration in the past tense with every number blank. */
.planned {
  border-left: 2px solid var(--amber-deep);
  padding: .85rem 1.1rem; margin: 1.2rem 0;
  background: rgba(255, 255, 255, .017);
  border-radius: var(--r-xs);
}
.planned b {
  display: block; margin-bottom: .35rem;
  font-family: var(--mono); font-size: .6rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--amber);
}


/* The condition cells became <button> for keyboard reach (WCAG 2.1.1); these
   strip the UA button chrome so the grid looks exactly as it did. */
.mx-c {
  border: 0; background: none; font: inherit; color: inherit;
  text-align: inherit; cursor: pointer; -webkit-appearance: none; appearance: none;
}
.mx-c:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* The opening line is display type, not the document's heading: the instrument's name in the
   record below is the page's one h1. This keeps the line looking exactly as it did. */
.intro .intro-title { margin: 0; font-weight: 600; letter-spacing: -.045em; }

/* ========================================================== function story
   The scroll-driven story that opens this page. It replaces the teardown that
   used to sit here; the teardown's own rules (.track, .stage, .card, .panel,
   .build, .counter and the .hud/.loader/.rail it shared) are still above in
   this file, untouched, so putting it back is a paste and not a merge.

   Everything below is scoped under .story for exactly that reason: .hud,
   .loader and .rail mean one thing to the teardown and another here, and
   `.story .hud` outranks a bare `.hud` without either having to be deleted.

   The display face is declared here because these instrument pages never
   needed it before — it lives in css/hub.css, which they do not load.
   Tokens (--mono, --sans, --fg, --faint, --line, --ease) come from
   ../css/polish.css; only --accent is set, per instrument. */
@font-face {
  font-family: "Oxanium Title";
  src: url("../../fonts/oxanium-600-latin.woff") format("woff");
  font-weight: 600; font-style: normal; font-display: block;
  unicode-range: U+0020-007E, U+00B7, U+2013-2014, U+2018-2019, U+201C-201D, U+2026;
}

.story { --accent: #46e08f; }



/* ------------------------------------------------------------------- stage */
/* z-index 3: the stage paints above the page's own fixed layers. Without it
   two of them were drawn over the 3D: the record's blueprint ghost (a fixed
   line drawing of the LPA inside .doc-wrap, whose z-index 2 lifts it above a
   z-auto story), which showed as a faint wireframe of the instrument through
   the right of every frame, and the horizon grid (body::after), a second
   perspective grid laid across the bench's own. Both are for the record and
   still show there. The header, the grain, the vignette and the scanline sit
   higher (41-50) and are unchanged. */
.story { position: relative; z-index: 3; }

.story .story-stage {
  position: sticky; top: 0;
  height: 100svh; min-height: 520px;
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 8%, rgba(120, 140, 170, .05), transparent 60%),
    var(--bg);
}

.story #gl { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }


/* -------------------------------------------------------------- title card */
.story .story-title {
  /* Left column, not centred: the photometer is a tall mast and DiOPAL is a
     wide block, and both read better holding one side of the frame with the
     type down the other than with words laid over the middle of them. */
  /* Higher and further in than the caption column: the title is the one piece
     of type that shares the frame with the whole instrument, so it sits nearer
     the middle and above centre, with the model holding the right. */
  position: absolute; left: clamp(1.4rem, 9vw, 7.5rem); top: 37%;
  transform: translateY(-50%);
  text-align: left; z-index: 4; pointer-events: none;
  width: min(86vw, 28rem);
  transition: none;
}

.story .story-title .eyebrow {
  font-family: var(--mono); font-size: .62rem; letter-spacing: .42em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 1.1rem;
}

.story .story-title .line {
  margin: 0;
  font-family: "Oxanium Title", var(--sans);
  font-weight: 600; letter-spacing: -.02em; line-height: 1.02;
  font-size: clamp(2.1rem, 6.2vw, 4.4rem);
  text-shadow: 0 0 64px rgba(0, 0, 0, .85);
}

.story .title-rule {
  display: flex; align-items: center; gap: .8rem;
  justify-content: flex-start; margin-top: 1.3rem;
}

.story .title-rule i { height: 1px; width: clamp(1.6rem, 5vw, 3rem); background: linear-gradient(90deg, var(--accent), transparent); }

.story .title-rule i:last-child { display: none; }

.story .title-rule span {
  font-family: var(--mono); font-size: .58rem; letter-spacing: .34em;
  text-transform: uppercase; color: var(--accent);
}


/* ---------------------------------------------------------------- captions */
.story .hud {
  position: absolute; left: clamp(1.1rem, 4vw, 4.2rem); bottom: clamp(1.6rem, 7vh, 5rem);
  width: min(30rem, 44vw); z-index: 5; pointer-events: none;
}

.story .cap {
  position: absolute; left: 0; bottom: 0; width: 100%;
  opacity: 0; visibility: hidden; will-change: opacity, transform;
}

.story .cap-tag {
  display: flex; align-items: center; gap: .7rem;
  font-family: var(--mono); font-size: .6rem; letter-spacing: .26em;
  text-transform: uppercase; color: var(--accent); margin-bottom: .75rem;
}

.story .cap-tag i { height: 1px; width: 1.9rem; background: var(--accent); opacity: .6; display: block; }

.story .cap-name {
  font-family: "Oxanium Title", var(--sans); font-weight: 600;
  font-size: clamp(1.35rem, 2.5vw, 2.05rem); letter-spacing: -.015em; line-height: 1.1;
}

.story .cap-rule { height: 1px; width: 3.4rem; background: var(--line); margin: .85rem 0 .8rem; }

.story .cap p {
  margin: 0; max-width: 34ch;
  font-size: clamp(.86rem, 1.05vw, .98rem); line-height: 1.62; color: #c3cbd6;
  text-wrap: pretty;
}

.story .cap p b, .story .cap p strong { color: var(--fg); font-weight: 600; }

.story .cap p em { color: var(--accent); font-style: normal; }


/* -------------------------------------------------------------- act rail */
.story .rail {
  position: absolute; right: clamp(.9rem, 2.2vw, 2.2rem); top: 50%;
  transform: translateY(-50%);
  display: flex; flex-direction: column; gap: .62rem; z-index: 5; pointer-events: none;
}

.story .rail i {
  display: block; width: 14px; height: 2px; background: rgba(255, 255, 255, .16);
  transition: background .35s var(--ease), width .35s var(--ease);
}

.story .rail i.on { background: var(--accent); width: 24px; }


/* ---------------------------------------------------- loader and scroll cue */
.story .loader {
  position: absolute; inset: 0; display: grid; place-items: center; z-index: 8;
  background: var(--bg); color: var(--faint);
  font-family: var(--mono); font-size: .62rem; letter-spacing: .3em; text-transform: uppercase;
  transition: opacity .7s var(--ease);
}

.story .loader.gone { opacity: 0; pointer-events: none; }

.story .scroll-cue {
  position: absolute; left: 50%; bottom: 2.1rem; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: .55rem;
  font-family: var(--mono); font-size: .56rem; letter-spacing: .38em;
  text-transform: uppercase; color: var(--faint); z-index: 5; pointer-events: none;
}

.story .scroll-cue i { display: block; width: 1px; height: 34px; background: linear-gradient(180deg, var(--faint), transparent); }


/* ------------------------------------------------------------------ phones */
@media (max-width: 860px) {

  .story .hud { width: auto; right: clamp(1.1rem, 4vw, 2rem); bottom: 1.4rem; }

  .story .cap p { max-width: none; font-size: .9rem; }

  .story .cap-name { font-size: 1.3rem; }

  .story .rail { display: none; }
}


@media (prefers-reduced-motion: reduce) {

  .story .cap, .story .story-title { transition: none !important; }
}

/* --- this page's own --- */

  /* 1400vh, not 1000. The camera does nearly all of its travel in the
     last 45% of each act, so a 100 px wheel notch was moving the picture
     by most of a screen and the scroll read as jerky. A longer track is
     the direct fix: the same moves, spread over 40% more scrolling. */
  .story { height: 1400vh; }


  .story .scrim {
    /* Sized to the caption, not to the screen. It used to be 62% / 44rem wide,
       which at 1500px reached 704px — 160px past the caption's right edge and
       across the left 200px of the rack in the overhead act, where its diagonal
       tail sat over the plate at about 20% alpha and read as a dark band down
       the plate's edge. Three rounds went looking for that in the shadow map.
       The caption is left: clamp(1.1rem,4vw,4.2rem) + width: min(30rem,44vw),
       but the TEXT inside it is capped at 34ch, so its right edge is bounded by
       the font, not the viewport — measured at 396px at 1500 wide, about the
       same at 1900. 30rem puts the gradient's zero at 442px: past the text,
       short of the rack, on every desktop width. */
    position: absolute; left: 0; bottom: 0; width: min(30rem, 52vw); height: 62%;
    z-index: 4; pointer-events: none;
    /* `to right`, not 105deg -- see the photometer stylesheet for the
       measurement. The tilt put the gradient's zero 99px past this element's
       right edge, so the fade was being clipped mid-way and left a hard
       vertical cut at x = 480. Narrowing 44rem -> 30rem earlier moved that cut;
       it did not remove it. Measured at x 481: step +8.69 before, -1.78 after,
       the same as removing the scrim altogether. */
    background: linear-gradient(to right, rgba(3,5,6,.93) 0%, rgba(3,5,6,.76) 44%, rgba(3,5,6,.22) 76%, rgba(3,5,6,0) 92%);
    /* The top edge fades out. With a hard edge, anything bright behind it — the
       lifted tubes in act 5 — showed a horizontal step where the scrim began. */
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 34%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 34%);
  }


  /* column labels, placed from the 3D grid each frame */
  .story #labels { position: absolute; inset: 0; z-index: 5; pointer-events: none; }

  .story .collab {
    position: absolute; left: 0; top: 0; opacity: 0; visibility: hidden;
    font-family: var(--mono); text-align: center; white-space: nowrap;
    will-change: transform, opacity;
  }

  .story .collab b { display: block; font-size: .8rem; font-weight: 600; color: #eef3f8; letter-spacing: .02em; }

  .story .collab b span { font-size: .55rem; color: var(--faint); margin-left: .15em; }

  .story .collab i {
    display: block; font-style: normal; font-size: .52rem; letter-spacing: .24em;
    margin-top: .2rem; color: #8b95a3;
  }

  .story .collab.green b { color: #7df0b5; }

  .story .collab.red b { color: #ff8d81; }


  /* the PWM waves, act 5 */
  .story #duty { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 4; opacity: 0; pointer-events: none; }


  .story .endline {
    position: absolute; left: clamp(1.1rem, 4vw, 4.2rem); top: 50%; transform: translateY(-50%);
    z-index: 6; opacity: 0; visibility: hidden; pointer-events: none;
    font-family: "Oxanium Title", var(--sans); font-weight: 600;
    font-size: clamp(1.5rem, 3.4vw, 2.6rem); letter-spacing: -.02em; line-height: 1.12;
    max-width: 20ch; text-shadow: 0 0 50px rgba(0,0,0,.9);
  }

  .story .endline em { color: var(--accent); font-style: normal; }


  @media (max-width: 760px) {

    /* Six column labels cannot sit side by side under a 390 px grid — they
       collided into one grey smear. The grid act keeps its picture; the
       conditions are named in the caption instead. */
    .story .collab { display: none; }
}

.doc-wrap {
  --blend-h: clamp(170px, 20vh, 300px);
  --blend-glow: rgba(70, 224, 143, .11);
}


/* The seam itself. The stage is sticky inside the track, so when the record
   finally arrives it is the stage's own bottom edge that meets it — which is
   why matching colours across that edge is the whole job. The render's bottom
   row is whatever the frame happens to hold there (floor, cable, instrument),
   so instead of trying to match it, the last 16vh of the stage is faded to the
   page's own #05060a. Both sides of the seam are then the same colour and the
   band below carries on from it.

   It sits under the captions (z 5) and over the scrim (z 4), and at 16vh it
   reads for the rest of the story as the bottom vignette a frame like this
   wants anyway. */
.story .story-stage::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: clamp(120px, 16vh, 215px); pointer-events: none; z-index: 4;
  background: linear-gradient(to bottom,
    rgba(5, 6, 10, 0) 0%, rgba(5, 6, 10, .30) 42%,
    rgba(5, 6, 10, .74) 74%, rgb(5, 6, 10) 100%);
}

/* ---------------------------------------------------- story -> record blend
   The record used to begin on a 1px rule laid straight across the stage: dark
   3D, hard line, paper. That rule is what made the two halves of the page read
   as two pages. It is gone, and in its place the record opens through a band
   that starts at the stage's own colour and dissolves into the page's, so the
   instrument fades into the document instead of being cut off it.

   The band is a real element, not a pseudo: ../css/polish.css loads after this
   file and already owns both .doc-wrap::before (the cursor glow) and ::after
   (the watermark), so a pseudo here loses some properties to it and keeps
   others, which is worse than losing outright.

   Drawn in both themes deliberately. In the light record it crosses the whole
   distance from #05060a to white; in the dark one there is almost no distance
   to cross and the band simply keeps the seam from being an edge. The colour
   it starts from is written out rather than taken from --bg, because --bg is
   the thing changing underneath it. */
.doc-wrap { border-top: 0; padding-top: var(--blend-h); }
.story-blend {
  position: absolute; left: 0; right: 0; top: 0;
  height: var(--blend-h); pointer-events: none; z-index: 0;
  background:
    /* A breath of the instrument's own colour across the crossing, so the
       dissolve carries the story's light into the page rather than going grey.
       Centred well down the band, not at its top: peaked at the top it put a
       warm bar right on the seam and made a worse edge than the rule it
       replaced — measured, rgb(33,23,16) against rgb(5,6,10) one pixel above. */
    radial-gradient(120% 74% at 50% 64%, var(--blend-glow) 0%, transparent 58%),
    linear-gradient(to bottom,
      rgb(5, 6, 10) 0%,
      rgba(5, 6, 10, .90) 26%,
      rgba(5, 6, 10, .58) 50%,
      rgba(5, 6, 10, .24) 74%,
      rgba(5, 6, 10, 0) 100%);
}

  /* The opening's right-hand column, the same one the photometer carries.
     The title holds the left, the instrument the middle; without this the
     right third of the first frame is empty. Every number is already on the
     page — the two wavelengths, 24 cultures, six conditions. */
  .story .title-stats {
    position: absolute; right: clamp(1.4rem, 7vw, 6rem); top: 37%;
    transform: translateY(-50%);
    z-index: 4; pointer-events: none; list-style: none; margin: 0; padding: 0;
    text-align: right; opacity: 0; visibility: hidden;
  }

  .story .title-stats li { margin: 0 0 1.45rem; }

  .story .title-stats li:last-child { margin-bottom: 0; }

  .story .title-stats b {
    font-family: var(--mono); font-weight: 600; font-size: clamp(1.1rem, 2.1vw, 1.6rem);
    color: #eef3f8; letter-spacing: .01em;
  }

  .story .title-stats span { font-family: var(--mono); font-size: .62rem; color: var(--faint); margin-left: .3rem; }

  .story .title-stats i {
    display: block; font-style: normal; font-family: var(--mono);
    font-size: .54rem; letter-spacing: .26em; text-transform: uppercase;
    color: #8b95a3; margin-top: .3rem;
  }

  @media (max-width: 760px) {

    /* four numbers down the side of a 390 px frame collide with the mast */
    .story .title-stats { display: none; }
}

/* ------------------------------------------------------------ landing chrome
   Four corner brackets and one slow sweep across the stage, both keyed to the
   title's fade by the scene so they dress the landing and nothing else. Kept
   thin and low: the point is that the opening frame reads as an instrument
   being presented, not that anyone notices a bracket. */
.story .hero-frame {
  position: absolute; inset: 0; z-index: 4; pointer-events: none;
  opacity: 0; visibility: hidden;
}
.story .hero-frame i {
  position: absolute; width: 30px; height: 30px;
  border: 1px solid var(--accent); opacity: .62;
}
/* The top pair clears the fixed header, which is 75px tall and sits at z 50
   over the stage: at a 22px inset both of them were behind it. */
.story .hero-frame i.hf-tl { left: 26px; top: 92px; border-right: 0; border-bottom: 0; }
.story .hero-frame i.hf-tr { right: 26px; top: 92px; border-left: 0; border-bottom: 0; }
.story .hero-frame i.hf-bl { left: 26px; bottom: 26px; border-right: 0; border-top: 0; }
.story .hero-frame i.hf-br { right: 26px; bottom: 26px; border-left: 0; border-top: 0; }
/* one pass every nine seconds, a fifth of a percent of the frame's luminance —
   enough to make the stage feel alive, not enough to read as a scanline */
.story .hero-scan { display: none; }  /* 15 Oct 2026, the owner: no scan bar at all */
@media (max-width: 760px) {
  .story .hero-frame i { width: 18px; height: 18px; }
  .story .hero-frame i.hf-tl, .story .hero-frame i.hf-tr { top: 84px; }
  .story .hero-frame i.hf-bl, .story .hero-frame i.hf-br { bottom: 14px; }
  .story .hero-frame i.hf-tl, .story .hero-frame i.hf-bl { left: 14px; }
  .story .hero-frame i.hf-tr, .story .hero-frame i.hf-br { right: 14px; }
}
@media (prefers-reduced-motion: reduce) {
  .story .hero-scan { animation: none; opacity: 0; }
}


/* ==========================================================================
   The record, rebuilt to the team's writing doc (2 Oct 2026, night)
   --------------------------------------------------------------------------
   The document half now follows the doc's "Component Page: DiOPAL", sections
   2-10. These rules are the few pieces that page needed and the site did not
   have yet; everything else (part marks, frames, autodraw plates, .limits,
   .filter-steps, callouts, the amber .todo marks in ../css/wiki-align.css) is
   reused as it was. Colours come from the team wiki's tokens, which
   wiki-align.css defines on body.doc-light; each has a dark fallback for the
   moment before the page turns to paper.
   ========================================================================== */

/* the two wavelengths, at reading weight on paper */
.doc { --g-ink: #35c46f; --r-ink: #ff6a55; }
body.doc-light .doc { --g-ink: #137a3c; --r-ink: #c1392a; }

/* ---- key sentences ------------------------------------------------------
   wiki-align.css gives .mark the amber tint, and on this page amber now means
   "not on record yet". A highlighted claim must not read as a missing one, so
   here the highlight is the team wiki's leaf tint instead. */
body.doc-light .doc-wrap .doc span.mark {
  background: var(--w-leaf-100);
  box-shadow: inset 0 -1px 0 var(--w-leaf-200);
}

/* ---- tier brightness in the two schematics -------------------------------
   Low, mid and high are drawn as three fills of the same colour. It marks the
   tier, nothing more: the real levels are PWM duty cycles, not on record. */
.doc .autodraw .g.t1 { fill: rgba(53, 196, 111, .14); }
.doc .autodraw .g.t2 { fill: rgba(53, 196, 111, .42); }
.doc .autodraw .g.t3 { fill: rgba(53, 196, 111, .88); }
.doc .autodraw .r.t1 { fill: rgba(255, 106, 85, .14); }
.doc .autodraw .r.t2 { fill: rgba(255, 106, 85, .42); }
.doc .autodraw .r.t3 { fill: rgba(255, 106, 85, .88); }
body.doc-light .doc .autodraw .g.t1 { fill: rgba(23, 132, 63, .12); }
body.doc-light .doc .autodraw .g.t2 { fill: rgba(23, 132, 63, .40); }
body.doc-light .doc .autodraw .g.t3 { fill: rgba(23, 132, 63, .85); }
body.doc-light .doc .autodraw .r.t1 { fill: rgba(193, 57, 42, .12); }
body.doc-light .doc .autodraw .r.t2 { fill: rgba(193, 57, 42, .40); }
body.doc-light .doc .autodraw .r.t3 { fill: rgba(193, 57, 42, .85); }

/* ---- prose lessons: .limits at reading size ------------------------------ */
.limits.prose { gap: 1.2rem; margin: 1.3rem 0 1.5rem; }
.limits.prose p { font-size: 1rem !important; line-height: 1.72; color: var(--muted); }
.limits.prose h4 { font-size: 1rem; font-weight: 650; color: var(--fg); margin: 0 0 .35rem; display: block; }
@media (min-width: 900px) {
  .limits.prose.two { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1.6rem; }
}
body.doc-light .limits > div { border-left-color: var(--w-leaf-200); }

/* ---- the four cycle-3 changes: .filter-steps carrying a part name -------- */
.filter-steps.changes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.filter-steps.changes b { letter-spacing: .06em; }
.filter-steps.changes strong { display: block; color: var(--fg); font-weight: 650; font-size: .92rem; margin-bottom: .3rem; }
.filter-steps.changes p { font-size: .88rem !important; line-height: 1.6; color: var(--muted); }
body.doc-light .filter-steps.changes { background: var(--w-line); border-color: var(--w-line); }
body.doc-light .filter-steps.changes b { color: var(--w-leaf-700); }

/* ---- photo groups ---------------------------------------------------------- */
.frames.trio { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.frames.duo { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.frames.duo .frame-img { aspect-ratio: 1 / 1; }
.frame.hero.solo { max-width: 380px; }
.frame.hero.solo.land { max-width: 520px; }
.frame.hero.solo.land .frame-img { aspect-ratio: 1000 / 835; }
@media (min-width: 1360px) {
  .doc .sec > figure.frame.hero.solo > .frame-img { max-width: 380px; }
  .doc .sec > figure.frame.hero.solo.land > .frame-img { max-width: 520px; }
}
@media (max-width: 700px) {
  .frames.trio, .frames.duo { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .7rem; }
  .frames.duo .frame-img { aspect-ratio: 3 / 4; }
  .frames.trio > .frame:nth-child(3) { grid-column: 1 / -1; }
  .frames.trio > .frame:nth-child(3) .frame-img { aspect-ratio: 4 / 3; }
}

/* ---- tables on paper: the team wiki's light header and hairlines ---------- */
.doc :is(table.lux, table.chan, table.mat) caption {
  font-family: var(--sans); font-size: .875rem; letter-spacing: 0; text-transform: none;
  color: var(--muted); padding-bottom: .55rem;
}
.doc :is(table.lux, table.chan, table.mat) caption .fignum { font-family: var(--sans); font-size: inherit; letter-spacing: 0; text-transform: none; font-weight: 700; }
.doc :is(table.lux, table.chan, table.mat) caption .fignum::after { content: "."; }
body.doc-light .doc :is(table.lux, table.chan, table.mat) caption .fignum { color: var(--w-leaf-700); }
body.doc-light .doc :is(table.lux, table.chan, table.mat) td,
body.doc-light .doc table.lux tbody th { border-bottom: 1px solid var(--w-line); }
/* the HUD corner bracket polish.css draws on every .table-scroll lands on the
   last cell of a hairline table; these tables have their own frame */
.doc .table-scroll.plain::after { display: none; }

/* ---- the 4 x 5 lux tables (4.3) -------------------------------------------
   A cell's shade is the matched group its LED went into; unshaded LEDs were
   not used. The shades are the cells' own colour at three strengths, and the
   reading stays in ink on all of them (worst case 8:1). */
.lux-key {
  display: flex; flex-wrap: wrap; gap: .35rem 1.15rem;
  margin: 1.1rem 0 .2rem; font-size: .84rem; color: var(--muted);
}
.lux-key span { display: inline-flex; align-items: center; gap: .45rem; }
.lux-key i {
  width: 17px; height: 17px; border-radius: 3px; display: inline-block;
  border: 1px solid var(--line-2);
}
.lux-key i.t-low  { background: linear-gradient(135deg, rgba(23,132,63,.12) 50%, rgba(193,57,42,.12) 50%); }
.lux-key i.t-mid  { background: linear-gradient(135deg, rgba(23,132,63,.26) 50%, rgba(193,57,42,.26) 50%); }
.lux-key i.t-high { background: linear-gradient(135deg, rgba(23,132,63,.42) 50%, rgba(193,57,42,.42) 50%); }
.lux-key i.t-none { background: transparent; }
.lux-pair {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 1.4rem; margin: .4rem 0 1.4rem;
}
.lux-pair .table-scroll { margin: .8rem 0 0; }
table.lux { min-width: 0; table-layout: fixed; font-size: .95rem; }
table.lux th, table.lux td { text-align: center; padding: .5rem .2rem; }
table.lux thead th:first-child, table.lux tbody th { width: 2.3rem; }
table.lux tbody th { font-family: var(--mono); font-size: .8rem; color: var(--dim); letter-spacing: 0; }
.doc table.lux td { color: var(--fg); font-weight: 500; font-variant-numeric: tabular-nums; }
.doc table.lux td[data-g="none"] { color: var(--faint); font-weight: 400; }
table.lux.green td[data-g="low"]  { background: rgba(23, 132, 63, .12); }
table.lux.green td[data-g="mid"]  { background: rgba(23, 132, 63, .26); }
table.lux.green td[data-g="high"] { background: rgba(23, 132, 63, .42); }
table.lux.red td[data-g="low"]  { background: rgba(193, 57, 42, .12); }
table.lux.red td[data-g="mid"]  { background: rgba(193, 57, 42, .26); }
table.lux.red td[data-g="high"] { background: rgba(193, 57, 42, .42); }
table.lux tbody td { border-left: 1px solid var(--bg); }
@media (max-width: 720px) { .lux-pair { grid-template-columns: minmax(0, 1fr); } }

/* ---- the six channels after rewiring -------------------------------------- */
table.chan { min-width: 0; table-layout: fixed; font-size: .95rem; }
table.chan th, table.chan td { text-align: center; padding: .5rem .25rem; }
.doc table.chan td { color: var(--fg); font-variant-numeric: tabular-nums; font-weight: 500; }
body.doc-light .doc table.chan thead th:nth-child(odd) { color: var(--g-ink); }
body.doc-light .doc table.chan thead th:nth-child(even) { color: var(--r-ink); }
/* the two readings the doc and the raw table disagree on */
.doc table.chan td.flag { background: #fff3eb; box-shadow: inset 0 -2px 0 #fdba8c; }
@media (max-width: 520px) {
  table.chan { font-size: .86rem; }
  table.chan th { padding: .45rem .1rem; }
}

/* ---- 4.4: spread, then matched --------------------------------------------- */
.fig.plate { margin: 2rem 0 2.2rem; }
body.doc-light .fig.plate {
  background: #fff; border: 1px solid rgba(15, 19, 25, .13); border-radius: var(--r-md);
  padding: 18px 18px 6px;
  box-shadow: 0 1px 1px rgba(15, 19, 25, .04), 0 18px 34px -22px rgba(15, 19, 25, .40);
}
.spread-chart { display: grid; gap: 1.3rem; min-height: 420px; }
.sp-head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .25rem 1rem; font-size: .84rem; color: var(--muted); margin-bottom: .1rem;
}
.sp-name { display: inline-flex; align-items: center; gap: .5rem; font-weight: 650; color: var(--fg); }
.sp-sw { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.sp-sw.green { background: var(--g-ink); }
.sp-sw.red { background: var(--r-ink); }
.sp-sum b { color: var(--fg); font-variant-numeric: tabular-nums; white-space: nowrap; }
.sp-sum i { font-style: normal; color: var(--faint); margin: 0 .45em; }
.sp-svg { display: block; overflow: visible; }
.sp-svg text { font-family: var(--mono); font-size: 11px; fill: var(--dim); }
.sp-svg .sp-tl { text-anchor: middle; }
.sp-svg .sp-unit { text-anchor: end; fill: var(--faint); }
.sp-svg .sp-gl { text-anchor: middle; fill: var(--fg); }
.sp-svg .sp-gn { text-transform: uppercase; letter-spacing: .08em; font-weight: 600; }
.sp-svg .sp-dim { text-anchor: middle; fill: var(--muted); font-weight: 600; }
.sp-ax, .sp-tk { stroke: var(--line-2); stroke-width: 1; }
.sp-br { stroke: var(--muted); stroke-width: 1; }
.sp-win { fill: rgba(127, 127, 127, .06); stroke: var(--line-2); stroke-dasharray: 3 3; }
.sp-guide { fill: none; stroke: var(--line-2); stroke-dasharray: 3 4; }
.sp-dot { stroke-width: 1; }
.sp-dot.off { fill: var(--bg); stroke: #8d96a1; stroke-width: 1.2; }
.sp-svg.green .sp-dot:not(.off) { stroke: var(--g-ink); }
.sp-svg.red .sp-dot:not(.off) { stroke: var(--r-ink); }
.sp-svg.green .t-low  { fill: #b8e3c6; } .sp-svg.green .t-mid  { fill: #5bb77f; } .sp-svg.green .t-high { fill: #17843f; }
.sp-svg.red .t-low    { fill: #f6c4bb; } .sp-svg.red .t-mid    { fill: #e2725d; } .sp-svg.red .t-high   { fill: #b8321f; }
.sp-svg rect.sp-cap { fill-opacity: .16; stroke-width: 1; }
.sp-svg.green rect.sp-cap { fill: #17843f; stroke: rgba(23, 132, 63, .45); }
.sp-svg.red rect.sp-cap { fill: #c1392a; stroke: rgba(193, 57, 42, .45); }

/* ---- 4.4 and the doc's two disagreements ------------------------------------ */
ul.flags { padding-left: 1.2rem; margin: .4rem 0 1.4rem; max-width: 68ch; }
ul.flags li { margin-bottom: .9rem; color: var(--muted); }
ul.flags li .todo { margin-top: .3rem; }

/* ---- key specifications: a datasheet ------------------------------------ */
dl.datasheet { margin: 1.3rem 0 1.6rem; border-top: 1px solid var(--line); }
dl.datasheet > div {
  display: grid; grid-template-columns: 10.5rem minmax(0, 1fr); gap: .3rem 1.2rem;
  padding: .66rem 0; border-bottom: 1px solid var(--line);
}
dl.datasheet dt {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--amber); padding-top: .22rem;
}
dl.datasheet dd { margin: 0; font-size: 1rem; line-height: 1.6; color: var(--fg); }
dl.datasheet .ds-head { border-bottom: 0; padding-bottom: .1rem; }
dl.datasheet .ds-head dt { color: var(--muted); grid-column: 1 / -1; }
dl.datasheet .ds-head dd { display: none; }
body.doc-light dl.datasheet { border-top-color: var(--w-leaf-200); }
body.doc-light dl.datasheet > div { border-bottom-color: var(--w-line); }
body.doc-light dl.datasheet dt { color: var(--w-leaf-700); }
body.doc-light dl.datasheet .ds-head dt { color: var(--muted); }
dl.datasheet.cad-dims { border-top: 0; margin-top: 1.9rem; }
@media (max-width: 600px) {
  dl.datasheet > div { grid-template-columns: minmax(0, 1fr); gap: .1rem; }
}

/* ---- the CAD parts plate, with numbered balloons --------------------------- */
.frame.cad .frame-img { aspect-ratio: 16 / 9; }
body.doc-light .frame.cad .frame-img { background: #f3f5f7; }
.frame.cad:hover img { transform: none; }
.frame.cad .frame-img::before { display: none; }
.balloon {
  position: absolute; z-index: 3; pointer-events: none;
  transform: translate(-50%, -50%);
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  font: 700 11px/1 var(--mono); color: #fff;
  background: var(--w-leaf-700, #23684a);
  box-shadow: 0 0 0 2px #fff, 0 2px 6px rgba(0, 0, 0, .28);
}
.balloon.pcb { background: #3f5468; }
.cad-key { white-space: normal; }
@media (max-width: 700px) {
  .balloon { width: 20px; height: 20px; }
}

/* ---- reproduction tables: on a phone each row becomes a card ------------- */
table.mat { min-width: 600px; }
table.mat.prints, table.mat.files { min-width: 0; }
table.mat td { vertical-align: top; }
table.mat .fsize { font-family: var(--mono); font-size: .75rem; color: var(--faint); white-space: nowrap; margin-left: .3rem; }
table.mat tr.extra td { color: var(--muted); }
@media (max-width: 700px) {
  table.mat, table.mat.prints, table.mat.files { min-width: 0; }
  table.mat thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  table.mat, table.mat tbody, table.mat tfoot, table.mat tr { display: block; width: 100%; }
  table.mat caption { display: block; text-align: left; }
  table.mat tr { padding: .65rem .2rem .7rem; border-bottom: 1px solid var(--line); }
  body.doc-light table.mat tr { border-bottom-color: var(--w-line); }
  .doc table.mat td {
    display: grid; grid-template-columns: 6.6rem minmax(0, 1fr); gap: .7rem; align-items: baseline;
    padding: .16rem 0; border: 0 !important; text-align: left !important; white-space: normal !important;
    background: none !important;
  }
  .doc table.mat td::before {
    content: attr(data-label); font-family: var(--mono); font-size: 11px;
    letter-spacing: .06em; text-transform: uppercase; color: var(--dim); padding-top: .2rem;
  }
  .doc table.mat td:first-child { display: block; font-size: 1rem; font-weight: 650; color: var(--fg); padding-bottom: .25rem; }
  .doc table.mat td:first-child::before { content: none; }
  table.mat.files td:first-child { display: none; }
  table.mat.files td:nth-child(2) { display: block; font-size: 1rem; font-weight: 650; color: var(--fg); padding-bottom: .25rem; }
  table.mat.files td:nth-child(2)::before { content: none; }
  table.mat tfoot td:empty { display: none; }
  table.mat tfoot tr { border-bottom: 0; }
}


/* ---- the units note --------------------------------------------------------- */
body.doc-light .doc-wrap .doc aside.callout.callout--slate > .callout-label { color: var(--w-slate-700); }
.callout.units p { font-size: .95rem !important; line-height: 1.65; }

/* ---- a short amber note under a claim the doc and the data disagree on --- */
div.todo.note {
  margin: .5rem 0 1.2rem; padding: .55rem .8rem;
  font-size: .875rem; line-height: 1.55; font-weight: 500;
}
div.todo.note > b { display: inline; margin: 0 .55em 0 0; }
.doc div.todo > b { color: inherit; }
ul.flags li div.todo.note { margin-bottom: 0; }

/* ---- a name is not a drop cap ---------------------------------------------
   polish.css raises the first letter of each part's opening paragraph. Two of
   them open with "DiOPAL", and a raised D followed by "iOPAL" reads as a typo. */
body.doc-light .doc .part + .sec > p.nodrop:first-of-type::first-letter {
  float: none; font-size: inherit; line-height: inherit; padding: 0; color: inherit; font-weight: inherit;
}

/* the layout plate's headline figure, a size down so it clears the plate */
.doc .autodraw.layout text.big { font-size: 19px; }

/* ---- an amber label inside a sentence wraps with the sentence ------------
   As an inline-block a long label became a box on its own line and pushed the
   rest of the sentence below it on a phone. Inline, with its border cloned
   onto each line, it reads as part of the text. Short labels look the same. */
.doc .sec p span.todo, .doc dd span.todo, .doc figcaption span.todo {
  display: inline; -webkit-box-decoration-break: clone; box-decoration-break: clone;
  padding: .04em .42em; white-space: nowrap;
}
.doc .sec p span.todo.wrap, .doc dd span.todo.wrap { white-space: normal; }

/* ---- the array plate on a phone --------------------------------------------
   js/doc.js crops the drawing to the array itself in a column narrower than
   the drawing's 640px, so the grid is
   drawn near full size instead of scrolling sideways; the caption carries the
   side notes it drops. */
.doc .autodraw.layout.narrow svg { min-width: 0; overflow: hidden; }
.doc .autodraw.layout.narrow .side { visibility: hidden; }

/* phones: the smallest labels this page adds or reuses, held at 11px */
@media (max-width: 700px) {
  .filter-steps.changes b { font-size: 11px; }
  .doc .autodraw text.dim { font-size: 11.5px; }
  .doc-map .map-n { font-size: 11px; }
}
.doc td .todo sub { font-size: .9em; }


/* ==========================================================================
   Fixes after the two judges (3 Oct 2026, night)
   --------------------------------------------------------------------------
   The page loads before ../css/polish.css and ../css/wiki-align.css, so every
   rule here out-specifies the shared rule it adjusts rather than relying on
   order. Shared fixes that belong to all four component pages are not made
   here; they are listed for the coordinator in the night's FIX-LOG.
   ========================================================================== */

/* ---- running text on paper -------------------------------------------------
   wiki-align.css sets section prose in the team's near-black; the lessons in
   .limits blocks are prose too and were still slate. */
body.doc-light .doc-wrap .limits.prose p { color: #262626; }

/* ---- widows and orphans ------------------------------------------------- */
body.doc-light .doc-wrap :is(.sec > p, figcaption, .sec li, .limits p, div.todo, dl.datasheet dd) { text-wrap: pretty; }
body.doc-light .doc-wrap :is(.part > h2, .sec > h3, .limits h4) { text-wrap: balance; }

/* ---- a solo photo hugs its picture at every width -------------------------
   From 1360px polish.css stretches each hero frame across the column so its
   caption can sit in the margin; this page's portrait photos are capped at
   380px, so each floated in about 190px of empty board either side. A solo
   photo now keeps the plate it has below 1360px: the board fits the picture
   and the caption sits under it, as the small multiples in .frames always do.
   Full-width plates and diagrams keep the house margin caption. */
@media (min-width: 1360px) {
  body.doc-light .doc .sec > figure.frame.hero.solo { max-width: 380px; margin-left: auto; margin-right: auto; }
  body.doc-light .doc .sec > figure.frame.hero.solo.land { max-width: 520px; }
  body.doc-light .doc .sec > figure.frame.hero.solo > .frame-img { max-width: none; margin-left: 0; margin-right: 0; }
  body.doc-light .doc .sec > figure.frame.hero.solo > figcaption {
    position: static; width: auto; max-width: none; border-left: 0;
    margin: 12px 0 0; padding: 10px 2px 12px;
  }
  body.doc-light .doc .sec > figure.frame.hero.solo > figcaption b { display: inline-block; margin: 0 .55em 0 0; }
}

/* ---- 5.2: three photos, the drive among them ----------------------------- */
#fig-inside .frame-img img { object-position: center 30%; }

/* ---- the drive chain on a phone --------------------------------------------
   js/doc.js crops it to the bus, the three MOSFETs and the six columns when
   its column is narrower than the drawing's 640px, as it does the array
   plate; the software and Arduino boxes it drops are named in the caption. */
.doc .autodraw.drive.narrow svg { min-width: 0; overflow: hidden; }
/* both crops: in a column between a phone's and the drawing's own 640px, the
   cropped view is held at a reading size rather than blown up to the column */
.doc .autodraw.narrow svg { max-width: 440px; margin-left: auto; margin-right: auto; }

/* ---- sections the doc has headed but not written: one block per section ---- */
.doc .sec div.todo.plan ol { margin: .55rem 0 0; padding: 0; list-style: none; display: grid; gap: .5rem; }
.doc .sec div.todo.plan li { font-size: inherit; line-height: 1.6; margin: 0; color: inherit; }
body.doc-light .doc .sec div.todo.plan li > b { color: #262626; font-weight: 650; margin-right: .4em; }

/* ---- 9.1: a minor heading below 9.1 that is not a subsection --------------- */
body.doc-light .doc-wrap .sec > h4.minor {
  font-size: 1.05rem; font-weight: 700; letter-spacing: -.01em; color: var(--w-leaf-900);
  margin: 2.4rem 0 .6rem;
}

/* ---- 9.1: what is not on record is said once per table ---------------------
   A cell with no value shows a dash; the orange note under the table names
   what is missing. On a phone a dash cell is dropped, so each card lists only
   what is known. */
.doc table.mat td.nr { color: var(--faint); }
@media (max-width: 700px) { .doc table.mat td.nr { display: none; } }
body.doc-light .doc-wrap section.sec > p.tnote { font-size: .9rem; line-height: 1.65; color: var(--muted); margin: -.4rem 0 1.6rem; }
.doc .table-scroll + div.todo.note { margin-top: .9rem; }

/* ---- table numbers on a phone ------------------------------------------------
   polish.css floors every caption number at 11px on a phone; a table caption is
   14px, so its number shrank below the words it leads. wiki-align.css already
   lifts figure captions; table captions take the same fix here. */
@media (max-width: 700px) {
  body.doc-light .doc-wrap table caption .fignum { font-size: inherit !important; }
}

/* ---- the design files: the photometer's cards (photometer/css/style.css, "9 the design files" and "9.1"), copied
   so every instrument page offers its STLs the same way (owner, 17 Oct 2026: "standardize all the stl download
   sections to match photometer"). Each part, rendered from its own STL, sits in its card's bottom-right corner,
   cut off by the card's edge and fading toward the text. */
.doc .sec ol.files {
  list-style: none; margin: 1.3rem 0 1.6rem; padding: 0;
  display: grid; gap: .7rem; grid-template-columns: repeat(2, minmax(0, 1fr));
}
body.doc-light .doc-wrap section.sec > ol.files { max-width: none; }
.doc .sec ol.files > li {
  display: flex; gap: .8rem; margin: 0; padding: .85rem .95rem .8rem;
  border: 1px solid #e5e5e5; border-radius: .3125rem; background: #fff;
  position: relative; overflow: hidden; isolation: isolate;
}
.files .fn {
  flex: none; width: 1.6rem; height: 1.6rem; border-radius: 50%;
  display: grid; place-content: center; margin-top: .05rem;
  border: 1.5px solid var(--w-leaf-700, #23684a); font: 700 .8rem/1 var(--sans); color: var(--w-leaf-900, #14402b);
}
.files .fb { position: relative; z-index: 1; min-width: 0; }
.doc .sec ol.files > li > .fb { flex: 1 1 auto; }
.files .fb b { display: block; font-size: .98rem; color: #1f2933; }
.doc .sec .files .fb p { margin: .2rem 0 0; font-size: .88rem; line-height: 1.5; max-width: none; color: var(--muted); }
.doc .sec .files .fb p:not(.dl) { max-width: calc(100% - 5.5rem); }
.doc .sec .files .fb p.dl { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .9rem; margin-top: .55rem; }
.doc .sec .files .dl a {
  display: inline-flex; align-items: baseline; gap: .45rem;
  padding: .28rem .6rem; border-radius: .3125rem;
  border: 1px solid var(--w-leaf-200, #cfe4d8); background: var(--w-leaf-50, #f4f9f6);
  font: 700 .8rem/1.3 var(--sans); color: var(--w-leaf-900, #14402b); text-decoration: none;
}
.doc .sec .files .dl a span { font: 500 .74rem/1.3 var(--mono); color: var(--w-leaf-700, #23684a); }
.doc .sec .files .dl a:hover, .doc .sec .files .dl a:focus-visible {
  border-color: var(--w-leaf-500, #4f9c6f); background: #fff; color: var(--w-leaf-900, #14402b);
}
/* the download buttons outrank the prose-link rules (wiki-align.css and the page's own) */
body.doc-light .doc-wrap .doc .sec .files p.dl a,
body.doc-light .doc-wrap .sec ol.files .dl a:not(.xref):not(.pick-link) {
  color: var(--w-leaf-900, #14402b); text-decoration: none; background: var(--w-leaf-50, #f4f9f6);
}
body.doc-light .doc-wrap .doc .sec .files p.dl a:hover,
body.doc-light .doc-wrap .doc .sec .files p.dl a:focus-visible { background: #fff; }
.files .f-part {
  position: absolute; z-index: 0; right: -20px; bottom: -24px; width: 158px; height: 124px;
  object-fit: contain; object-position: right bottom;
  pointer-events: none; user-select: none; opacity: .88;
  -webkit-mask-image: radial-gradient(130% 130% at 100% 100%, #000 45%, rgba(0,0,0,.6) 64%, transparent 86%);
          mask-image: radial-gradient(130% 130% at 100% 100%, #000 45%, rgba(0,0,0,.6) 64%, transparent 86%);
  transition: transform .45s cubic-bezier(.2,.8,.2,1), opacity .3s ease;
}
.doc .sec ol.files > li:hover .f-part, .doc .sec ol.files > li:focus-within .f-part { transform: translate(-6px, -6px); opacity: 1; }
@media (max-width: 700px) {
  .doc .sec ol.files { grid-template-columns: 1fr; }
  .files .f-part { width: 132px; height: 108px; right: -18px; bottom: -20px; }
}
@media (prefers-reduced-motion: reduce) { .files .f-part { transition: none; } }
@media print { .files .f-part { display: none; } }


/* ==========================================================================
   Polish round (3 Oct 2026, afternoon)
   --------------------------------------------------------------------------
   The owner asked for the record to be easier to follow and to show more of
   the season's work, with the DBTL cycles as its backbone. Each block says what
   it adds and where its content comes from. Same load-order rule as the block
   above: this sheet loads before polish.css and wiki-align.css, so each rule
   out-specifies the shared rule it adjusts.
   ========================================================================== */

/* (§2's "three cycles at a glance" strip was removed on 17 Oct 2026, evening, with its markup.) */

/* ---- 5.1: each change card shows the part it is tagged with ---------------
   The renders are the 9.3 file cards' own (photos/parts/), each drawn from its
   part's STL in the colour it was printed; the tube holder is the one extra,
   rendered white because cycle 3's holder was white (5.3). Floated, so the
   card's text runs beside the part and then under it. */
.filter-steps.changes.with-parts > div { position: relative; overflow: hidden; }
.filter-steps.changes.with-parts p { text-wrap: pretty; }   /* judge pass: no one-word last line beside the float */
.filter-steps.changes .chg-part {
  float: right; display: block; width: 124px; height: auto; margin: -.25rem -.35rem .35rem .8rem;
  pointer-events: none; user-select: none;
}
.filter-steps.changes .chg-pair { position: relative; width: 132px; height: 92px; }
.filter-steps.changes .chg-pair img { position: absolute; width: 96px; height: auto; }
.filter-steps.changes .chg-pair img:first-child { left: 0; top: 0; }
.filter-steps.changes .chg-pair img:last-child { right: 0; bottom: 0; }
/* the code card's pictogram: a plain pulse-width square wave, no duty cycle implied */
.filter-steps.changes .chg-pwm { width: 104px; margin: .5rem .2rem .6rem .9rem; overflow: visible; }
.chg-pwm path { fill: none; stroke: var(--w-leaf-700, #3ddc8b); stroke-width: 2.4; stroke-linejoin: round; stroke-linecap: round; }
.chg-pwm path.ax { stroke: var(--w-leaf-200, rgba(61,220,139,.3)); stroke-width: 1.5; }
@media (max-width: 700px) {
  .filter-steps.changes.with-parts { grid-template-columns: minmax(0, 1fr); }
  .filter-steps.changes .chg-part { width: 104px; }
  .filter-steps.changes .chg-pair { width: 112px; height: 80px; }
  .filter-steps.changes .chg-pair img { width: 82px; }
  .filter-steps.changes .chg-pwm { width: 88px; }
}

/* ---- 5.2: the drive chain as built, cycle 2 beside cycle 3 -----------------
   One figure, two photos, an arrow between: a before and after reads as one
   comparison with one caption, not as two unrelated pictures. Each photo still
   opens in the lightbox. */
.doc .sec > figure.frame.pair { max-width: 640px; margin-left: auto; margin-right: auto; }
.frame.pair .pair-row {
  display: grid; grid-template-columns: minmax(0, 1fr) 30px minmax(0, 1fr); align-items: start;
}
.frame.pair .frame-img { aspect-ratio: 4 / 5; }
.frame.pair .frame-img img.c3-inside { object-position: center 28%; }
.pair-cell { min-width: 0; }
.pair-arrow {
  align-self: center; justify-self: center; margin-bottom: 2.6rem;
  width: 11px; height: 11px; margin-left: -5px;
  border-top: 2px solid var(--w-leaf-500, #4f9c6f); border-right: 2px solid var(--w-leaf-500, #4f9c6f);
  transform: rotate(45deg);
}
.pair-tag { display: block; margin: .55rem 0 0; font-size: .8125rem; line-height: 1.45; color: var(--muted); }
.pair-tag b {
  display: block; margin-bottom: .1rem; font: 700 11px/1.3 var(--sans); letter-spacing: .08em;
  text-transform: uppercase; color: var(--w-leaf-700, #3ddc8b);
}
body.doc-light .pair-tag { color: #4a5560; }
/* the two assembled photos that follow: square crops, as wide as the pair */
.doc .sec > .frames.duo { max-width: 640px; margin-left: auto; margin-right: auto; }
#fig-enclosed .frame-img img { object-position: center 60%; }
@media (max-width: 700px) {
  .frame.pair .pair-row { grid-template-columns: minmax(0, 1fr) 20px minmax(0, 1fr); }
  .pair-arrow { width: 9px; height: 9px; margin-left: -4px; margin-bottom: 3.4rem; }
}

/* ---- 5.3: the shaker and the break, side by side -------------------------- */
.doc .sec > .frames.duo.land { max-width: none; }
.frames.duo.land .frame-img { aspect-ratio: 6 / 5; }
@media (max-width: 700px) {
  .doc .sec > .frames.duo.land { grid-template-columns: minmax(0, 1fr); }
  .frames.duo.land .frame-img { aspect-ratio: 6 / 5; }
}

/* ---- 9.1 printed parts: each part beside its name --------------------------
   The same renders as the 9.3 file cards, so a reader can match a name in the
   table to a shape without leaving it. */
table.mat.prints td:first-child .v { display: inline-flex; align-items: center; gap: .75rem; }
table.mat.prints td { vertical-align: middle; }
table.mat.prints img.tp { flex: none; width: 58px; height: 40px; object-fit: contain; object-position: center; }
@media (max-width: 700px) {
  table.mat.prints img.tp { width: 52px; height: 36px; }
}
@media print { table.mat.prints img.tp { display: none; } }

/* ---- 4.4 Figure 6: the two numbers each panel is about, read first --------- */
.sp-head { align-items: flex-end; margin-bottom: .35rem; }
.sp-sum { display: inline-flex; flex-wrap: wrap; align-items: flex-end; gap: .2rem .7rem; }
.sp-sum > i { align-self: center; margin: 0; font-style: normal; color: var(--faint); font-size: 1rem; }
.sp-stat { display: inline-flex; flex-direction: column; line-height: 1.2; font-size: .75rem; color: var(--dim); }
.doc .sp-stat b {
  font-size: 1.3rem; line-height: 1.15; font-weight: 750; letter-spacing: -.01em; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.sp-panel.green .sp-stat b { color: var(--g-ink); }
.sp-panel.red .sp-stat b { color: var(--r-ink); }
.sp-panel .sp-stat:first-child b { color: var(--fg); }
@media (max-width: 700px) {
  .sp-stat { font-size: 11px; }
  .doc .sp-stat b { font-size: 1.12rem; }
}

/* ---- 6.2: the LPA in section ----------------------------------------------
   Outlines cut from the STLs at the second row of bores; fills are the print
   colours of the final build (black housing and holders, grey plate and
   sliders, green perf board), as in the parts plate. Balloons and dimension
   figures are HTML over the drawing, so they keep their size on a phone. */
.fig.plate.sect { padding-top: 22px; }
.sect-box { position: relative; max-width: 620px; margin: 0 auto; }
.sect-box svg { display: block; width: 100%; height: auto; overflow: visible; }
.sx { stroke-width: .45; stroke-linejoin: round; fill-rule: evenodd; }
.sx.p-box, .sx.p-led, .sx.p-tube { fill: #3a3f46; stroke: #1b1d21; }
.sx.p-plate, .sx.p-slide { fill: #8d959e; stroke: #4f5862; }
.sx.p-pcb { fill: #2f7a4f; stroke: #1d5a37; }
.sx-cl { fill: none; stroke: var(--w-leaf-500, #4f9c6f); stroke-width: .5; stroke-dasharray: 3 2.2; opacity: .8; }
.sx-dim { fill: none; stroke: #6b7580; stroke-width: .4; }
.sx-tick { fill: none; stroke: #39424c; stroke-width: .7; }
.sect-box .balloon { z-index: 3; }
.sx-lbl {
  position: absolute; z-index: 2; transform: translate(-50%, -50%); white-space: nowrap;
  font: 600 11.5px/1 var(--mono); letter-spacing: .02em; color: #39424c;
  background: #fff; padding: 2px 4px; border-radius: 2px;
}
.sx-lbl.sx-v { transform: translate(-50%, -50%) rotate(-90deg); }
@media (max-width: 700px) {
  .fig.plate.sect { padding: 14px 10px 6px; }
  .sx-lbl { font-size: 11px; padding: 1px 3px; }
}

/* ---- Figures 14 and 16: a part's balloon and its name light up together ---- */
.doc .frame.cad .balloon, .doc .sect-box .balloon { pointer-events: auto; cursor: default; transition: transform .15s ease, background-color .15s ease; }
.doc .balloon.hot { transform: translate(-50%, -50%) scale(1.3); background: var(--w-leaf-900, #14402b); z-index: 4; }
.doc .pk { border-radius: 3px; transition: background-color .15s ease, box-shadow .15s ease; }
.doc .pk.hot { background: var(--w-leaf-100, rgba(61, 220, 139, .18)); box-shadow: 0 0 0 2px var(--w-leaf-100, rgba(61, 220, 139, .18)); }
@media (prefers-reduced-motion: reduce) { .doc .balloon, .doc .pk { transition: none; } }
body.doc-light .doc .sec > figure.sect > figcaption { margin-top: 1.4rem; }

/* 9 Oct 2026 polish: section numbers sit next to their titles, as on the photometer page
   (photometer/css/style.css, "section numbers sit next to their titles, not in a 59px column").
   ../css/polish.css gives `.sec h3 i` a 2.6em min-width, which left a wide gap ("3.1      Design")
   on this page only. A heading that wraps keeps its number on the first line, as on the bioreactor page
   (`align-items: first baseline`; polish.css centres it). Delete this block to revert. */
body.doc-light[data-instrument="diopal"] .doc-wrap section.sec > h3 { gap: 0; align-items: first baseline; }
body.doc-light[data-instrument="diopal"] .doc-wrap section.sec > h3 > i { min-width: 0; }


/* ══════════════════ 14 Oct 2026: the teammate's edit doc ══════════════════
   Everything below is this page's own answer to "Hardware Page Edit" (LPA,
   PDF pp. 1-18). Scoped to the LPA page; the shared hwdoc/polish files are
   untouched. Delete this block to go back to the 13 Oct look (the markup
   changes are in the same commit). */

/* ---- the opening title: the name large and white on one line, the old
   headline under it smaller in green, then the question ---------------- */
.story .story-title.lpa-title { width: min(calc(100vw - 2.8rem), 52rem); }
.story .lpa-title .lpa-title__name {
  margin: 0;
  font-family: "Oxanium Title", var(--sans);
  font-weight: 600; letter-spacing: -.02em; line-height: 1.04;
  font-size: clamp(1.2rem, 7vw, 3.25rem);
  color: #fff; white-space: nowrap;
  text-shadow: 0 0 64px rgba(0, 0, 0, .85);
}
.story .lpa-title .line {
  margin: .7rem 0 0;
  font-size: clamp(1.05rem, 2.6vw, 1.75rem);
  line-height: 1.15; color: var(--accent);
}
.story .lpa-title .lpa-title__q {
  margin: 1.1rem 0 0; max-width: 26rem;
  font-size: clamp(.9rem, 1.2vw, 1.05rem); line-height: 1.55;
  color: rgba(226, 232, 240, .82);
  text-shadow: 0 0 24px rgba(0, 0, 0, .9);
}

/* ---- the overview: no box, no shadow, no grey fade above it ---------------- */
body[data-instrument="diopal"] .story-blend { display: none; }
body[data-instrument="diopal"] .doc-wrap { padding-top: clamp(3rem, 6vw, 5rem); }
body[data-instrument="diopal"] .hwsum.lpa-ov { margin-top: 0; }
body[data-instrument="diopal"] .lpa-ov .hwsum__inner {
  display: block; max-width: 760px; margin: 0 auto; padding: 0;
  background: none; box-shadow: none; border-radius: 0;
}
/* 17 Oct 2026, evening: set as the bioreactor's overview title is (bioreactor/css/record-edit.css: the large
   title on one line, sized to the column) and the two paragraphs as the record's prose (../css/hwdoc.css,
   "the prose"), so part 1 sits like the other pages' overviews. */
body[data-instrument="diopal"] .lpa-ov__title {
  margin: 0 0 .9rem;
  white-space: nowrap;
  font-size: clamp(1.4rem, 6.8vw, 3.6rem);
  font-weight: 750; line-height: 1.04; letter-spacing: -.034em;
  color: var(--w-ink);
}
body[data-instrument="diopal"] .lpa-ov .hwsum__body {
  max-width: 68ch; margin: 1rem 0 0;
  font-size: 1.0625rem; line-height: 1.7; letter-spacing: -.004em; color: #2b2b2e;
}
/* .hwsum's auto side margins make a grid item shrink to its content; with the 68ch measure above that
   pulled the overview in from the column's left edge, out of line with the record below */
body[data-instrument="diopal"] .hwsum.lpa-ov { width: 100%; }
body[data-instrument="diopal"] .lpa-ov__spec {
  margin: 1.4rem 0 0; padding-top: .9rem;
  border-top: 1px solid rgb(63 90 102 / .18);
  font-size: .9375rem; font-weight: 600; letter-spacing: .01em;
  color: var(--w-ink); font-variant-numeric: tabular-nums;
}
body[data-instrument="diopal"] .lpa-ov__spec i { font-style: normal; margin: 0 .35em; color: var(--w-ink-3); }

/* ---- no "Figure N" / "Table N" labels and no plate numbers ------------------- */
body[data-instrument="diopal"] .doc .fignum { display: none; }
body[data-instrument="diopal"] .doc .fignum + br { display: none; }
body.doc-light[data-instrument="diopal"] .doc .frame::after { content: none; }

/* ---- photos without their outline boxes (the doc: "do this for all") -------- */
body.doc-light[data-instrument="diopal"] .doc .frame {
  background: none; border: 0; box-shadow: none; padding: 0;
}
body.doc-light[data-instrument="diopal"] .doc .frame::before { content: none; }
body.doc-light[data-instrument="diopal"] .doc .frame figcaption { border-top: 0; padding: 0 2px; margin-top: .6rem; }

/* ---- lessons and limitations without the coloured bar on the left ----------- */
body[data-instrument="diopal"] .doc .limits > div { border-left: 0; padding-left: 0; }

/* ---- the green line under the array drawing ---------------------------------- */
body.doc-light[data-instrument="diopal"] .doc figcaption.lpa-subcap {
  color: var(--w-leaf-700, #23684a); font-weight: 550;
}

/* ---- cycle 1 build: the photo on the left, its text on the right -------------- */
.lpa-split {
  display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: clamp(1.25rem, 3vw, 2.25rem); align-items: start; margin: 1.2rem 0;
}
.lpa-split > .frame { margin: 0; max-width: none; }
.lpa-split > p { margin: 0; }
@media (max-width: 620px) {
  .lpa-split { grid-template-columns: minmax(0, 1fr); }
  .lpa-split > .frame { max-width: 340px; }
}

/* ---- the two plain tables of the final design ------------------------------- */
.doc table.lpa-kv { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.doc table.lpa-kv th, .doc table.lpa-kv td {
  text-align: left; vertical-align: top; padding: .62rem .9rem .62rem 0;
  border-bottom: 1px solid var(--w-line, rgba(15, 19, 25, .12));
}
.doc table.lpa-kv thead th {
  font-size: .75rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--w-ink-3, #6e6e73);
}
.doc table.lpa-kv tbody th { width: 38%; font-weight: 650; color: var(--w-ink, #1d1d1f); }
.doc table.lpa-kv td { color: var(--w-ink-2, #424245); }
.doc table.lpa-kv tbody th { font-size: inherit; letter-spacing: 0; text-transform: none; vertical-align: baseline; }
.doc table.lpa-kv td { vertical-align: baseline; }
.doc .table-scroll table.lpa-kv { min-width: 0; }
@media (max-width: 520px) { .doc table.lpa-kv tbody th { width: 42%; } .doc table.lpa-kv { font-size: .875rem; } }
body[data-instrument="diopal"] .lpa-ov__spec span { white-space: nowrap; }

/* ---- 15 Oct 2026, review fixes ---------------------------------------------- */
/* The overview has no paper box now, and the record only turns light (doc-light,
   polish.js) once it has climbed a third of the screen. Until then it is dark
   type on the dark page, so it gets light type for that phase. */
body[data-instrument="diopal"]:not(.doc-light) .lpa-ov__title,
body[data-instrument="diopal"]:not(.doc-light) .lpa-ov__spec,
body[data-instrument="diopal"]:not(.doc-light) #purpose > h2 { color: #eef2f6; }
body[data-instrument="diopal"]:not(.doc-light) .lpa-ov .hwsum__body { color: rgba(226, 232, 240, .86); }
body[data-instrument="diopal"]:not(.doc-light) .lpa-ov__spec { border-top-color: rgba(255, 255, 255, .14); }
body[data-instrument="diopal"]:not(.doc-light) .lpa-ov__spec i { color: rgba(226, 232, 240, .55); }
body[data-instrument="diopal"] .lpa-ov :is(h1, p) { transition: color .45s ease, border-color .45s ease; }
body[data-instrument="diopal"] .lpa-ov__spec i { margin: 0 .5em 0 .1em; }

/* the contents rail starts beside the overview, not under it */
@media (min-width: 1101px) {
  body[data-instrument="diopal"] .hwsum.lpa-ov { grid-column: 2; grid-row: 1; }
  body[data-instrument="diopal"] .doc-nav { grid-row: 1 / span 2; }
  body[data-instrument="diopal"] .doc { grid-row: 2; }
}

/* the opening title sits above the model on a landscape screen, as in the doc's mock-up */
@media (min-width: 900px) and (min-aspect-ratio: 5/4) {
  .story .story-title.lpa-title { top: 18%; }
}

/* cycle 3 build: the two boards centred like the photo under them, with run-in captions */
body[data-instrument="diopal"] .doc #fig-mosfets { margin-left: auto; margin-right: auto; }
body[data-instrument="diopal"] .doc .pair-tag b {
  display: inline; margin-right: .45em;
  font-family: inherit; font-size: inherit; font-weight: 700;
  letter-spacing: 0; text-transform: none; color: var(--w-ink, #1d1d1f);
}

/* the CAD render without its outline box, like the photos */
body[data-instrument="diopal"] .doc #fig-cad .frame-img { border: 0 !important; box-shadow: none !important; }

/* ---- 15 Oct 2026: the summary sheet is back, above the overview ------------
   The owner asked for the instructor's summary card on every instrument page.
   It is the plain .hwsum of ../css/hwdoc.css (paper, ledger, spec strip); the
   un-boxed overview keeps its .lpa-ov look. On a wide screen the sheet takes
   row 1 across all three columns, and the overview, the rail and the record
   each move down one row, so the rail still starts beside the overview. */
/* 17 Oct 2026, evening: part 1 starts as far under the sheet as the other pages' (the record's own top
   padding, ../css/hwdoc.css: 3.25rem, 2.25rem on a phone); it was 5rem. */
body[data-instrument="diopal"] .hwsum:not(.lpa-ov) + .hwsum.lpa-ov { margin-top: 3.25rem; }
@media (max-width: 600px) { body[data-instrument="diopal"] .hwsum:not(.lpa-ov) + .hwsum.lpa-ov { margin-top: 2.25rem; } }
@media (min-width: 1101px) {
  body[data-instrument="diopal"] .hwsum:not(.lpa-ov) { grid-row: 1; }
  body[data-instrument="diopal"] .hwsum.lpa-ov { grid-row: 2; }
  body[data-instrument="diopal"] .doc-nav { grid-row: 2 / span 2; }
  body[data-instrument="diopal"] .doc { grid-row: 3; }
}

/* ---- the opening title on a portrait screen (15 Oct 2026) ------------------
   The owner asked for the titles to be centred where they can be. On a landscape screen the LPA's
   title stays above the model, left, as in the doc's mock-up: the model is a wide block in the
   middle of the frame, and a centred title would sit on the tube block. On a portrait screen the
   portrait clip (below an aspect of about 0.91) puts the model in the top half, and the title used
   to lie across it (at 37% here, and under the menu on the integrated wiki, assets/css/nav-dark.css):
   it now hangs under the model, centred. The #story selectors outrank nav-dark.css. */
@media (max-aspect-ratio: 91/100) {
  body[data-instrument="diopal"] #story .story-title.lpa-title {
    top: 57%; left: 50%; translate: -50% 0; text-align: center;
  }
  body[data-instrument="diopal"] #story .lpa-title .lpa-title__q { margin-left: auto; margin-right: auto; }
  body[data-instrument="diopal"] #story .title-stats { display: none; }
}
/* A landscape phone: the model fills the middle of a short frame and there is no band above it, so
   the title moves into the left column, smaller and wrapping, without the question, and the four
   numbers stand down. */
@media (min-aspect-ratio: 91/100) and (max-height: 520px) {
  body[data-instrument="diopal"] #story .story-title.lpa-title {
    top: calc(50% + var(--nv-h, 68px) / 2); translate: 0 -50%; width: 30vw;
  }
  body[data-instrument="diopal"] #story .lpa-title .lpa-title__name { font-size: clamp(1rem, 3vw, 1.65rem); white-space: normal; }
  body[data-instrument="diopal"] #story .lpa-title .line { font-size: clamp(.8rem, 1.9vw, 1rem); margin-top: .4rem; }
  body[data-instrument="diopal"] #story .lpa-title .lpa-title__q { display: none; }
  body[data-instrument="diopal"] #story .title-stats { display: none; }
}

/* ---- 6.3: the run sketch's download card (17 Oct 2026, evening). The photometer's .pm-dl (its 7.3 and 10.3), its
   --pm-* tokens resolved to the wiki's --w-* ones, as the design-file cards were. ---- */
.pm-dl { display: grid; grid-template-columns: 3rem minmax(0, 1fr) auto; gap: 1rem; align-items: center; margin: 1rem 0 .4rem; padding: 1rem 1.1rem; border: 1px solid var(--w-line, rgba(15, 19, 25, .12)); border-radius: 14px; background: #fff; }
.pm-dl__ic { display: grid; place-items: center; width: 3rem; height: 3rem; border-radius: 10px; font-family: var(--mono); font-weight: 700; color: var(--w-leaf-700, #23684a); background: var(--w-leaf-50, #f4f9f6); }
.doc .pm-dl__tx b { display: block; color: var(--w-ink, #1d1d1f); }
.doc .pm-dl__tx p { margin: .2rem 0 0; font-size: .88rem; line-height: 1.5; }
.pm-dl__btn { padding: .45rem .9rem; border-radius: 999px; font-size: .82rem; font-weight: 600; }
body.hwreveal .doc-wrap .doc .pm-dl a.pm-dl__btn {
  display: inline-flex; align-items: baseline; gap: .45rem; white-space: nowrap;
  color: var(--w-leaf-900, #14402b); background: var(--w-leaf-50, #f4f9f6); background-image: none;
  border: 1px solid var(--w-leaf-200, #cfe4d8); text-decoration: none;
}
body.hwreveal .doc-wrap .doc .pm-dl a.pm-dl__btn span { font: 500 .74rem/1.3 var(--mono); color: var(--w-leaf-700, #23684a); }
body.hwreveal .doc-wrap .doc .pm-dl a.pm-dl__btn:is(:hover, :focus-visible) { border-color: var(--w-leaf-500, #4f9c6f); background: #fff; }
@media (max-width: 520px) { .pm-dl { grid-template-columns: 2.6rem minmax(0, 1fr); } .pm-dl__btn { grid-column: 2; justify-self: start; } }

/* ---- 18 Oct 2026: the reference list under References ------------------------- */
body[data-instrument="diopal"] .doc ol.refs {
  margin: 1.1rem 0 0; padding-left: 1.6em; font-size: .9em; line-height: 1.55;
  color: var(--w-ink-600, #4a4f57);
}
body[data-instrument="diopal"] .doc ol.refs li { margin: 0 0 .55rem; padding-left: .2em; overflow-wrap: anywhere; }
body[data-instrument="diopal"] .doc sup.cite { font-size: .68em; line-height: 0; margin-left: .1em; }
body[data-instrument="diopal"] .doc sup.cite a { text-decoration: none; }
body[data-instrument="diopal"] .doc .folds > .fold { min-width: 0; }

/* ---- User Testing and Feedback (18 Oct 2026) ------------------------------
   The same block on all four instrument pages. One entry per recorded event:
   when, who and the source on the left; what they did or said, and what
   changed, on the right. A list rather than a table, so it reads on a phone
   without sideways scrolling; one column under 700px. */
.doc .sec ol.ut-log {
  list-style: none; margin: 1.3rem 0 1.4rem; padding: 0;
  border-top: 1px solid #dcdcdc;
}
body.doc-light .doc-wrap section.sec > ol.ut-log { max-width: none; }
.doc .sec ol.ut-log > li {
  display: grid; grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
  gap: .5rem 1.75rem; margin: 0; padding: 1.05rem 0 1.1rem;
  border-bottom: 1px solid #dcdcdc;
  font-size: inherit; line-height: inherit;
}
.doc .sec ol.ut-log > li::before, .doc .sec ol.ut-log > li::after { content: none; display: none; }
.doc .sec .ut-who { min-width: 0; }
.doc .sec .ut-who > span { display: block; }
.doc .sec .ut-when {
  font: 700 .75rem/1.4 var(--sans, system-ui, sans-serif); letter-spacing: .06em;
  text-transform: uppercase; color: var(--w-leaf-700, #23684a);
}
.doc .sec .ut-name { margin-top: .3rem; font-weight: 650; line-height: 1.4; color: var(--fg, #1d1d1f); }
.doc .sec .ut-role { margin-top: .1rem; font-size: .875rem; line-height: 1.45; color: #4a4a4a; }
.doc .sec .ut-src { margin-top: .45rem; font-size: .8125rem; line-height: 1.45; color: #4a4a4a; }
.doc .sec .ut-body { min-width: 0; }
.doc .sec .ut-body p { margin: 0; max-width: 68ch; font-size: .96875rem; line-height: 1.62; color: #262626; }
.doc .sec .ut-body p + p { margin-top: .5rem; }
.doc .sec .ut-body .ut-k {
  display: inline; margin-right: .4rem;
  font: 700 .72rem/1 var(--sans, system-ui, sans-serif); letter-spacing: .07em;
  text-transform: uppercase; color: var(--w-leaf-700, #23684a);
}
.doc .sec p.ut-learn { margin-top: 1.1rem; }
@media (max-width: 700px) {
  .doc .sec ol.ut-log > li { grid-template-columns: minmax(0, 1fr); gap: .55rem; padding: .95rem 0 1rem; }
  .doc .sec .ut-who > span { display: inline; }
  .doc .sec .ut-name { margin-top: 0; }
  .doc .sec .ut-name::before { content: " \00b7  "; color: #6a6a6a; font-weight: 400; }
  .doc .sec .ut-role, .doc .sec .ut-src { display: block !important; }
  .doc .sec .ut-body p { font-size: 1rem; }
}

/* ---- 5.2 Design Files: each card's print, from the slicer (18 Oct 2026) ----
   The removed 5.2 Printed Parts table's filament, grams and cost per print, moved onto the cards. */
.doc .sec .files .fb p.fprint { margin-top: .45rem; font: 500 .78rem/1.45 var(--sans); color: var(--dim); font-variant-numeric: tabular-nums; }
.doc .sec .files .fb p.fprint .swatch { border-color: rgba(15, 19, 25, .18); margin-right: .4rem; }
