/* pacific-design.com — latent-space design system (v2, AI redesign).
   Deep indigo void, one violet→cyan spectral gradient as the sole identity
   accent, monospace system labels, live canvas visualizations. Dark by
   design — this site commits to the night palette. */

:root {
  --void:    #0A0E1A;
  --panel:   #10172A;
  --panel-2: #141D33;
  --line:    #232E4D;
  /* form-control borders need 3:1 against their background (WCAG 1.4.11);
     --line is 1.4:1 and is for decorative rules only */
  --ctl:     #556694;
  --ink:     #E8EBF5;
  --muted:   #97A0BC;
  --vio:     #8B78FF;
  --vio-hi:  #A99BFF;
  --cyan:    #52E0EE;
  --grad: linear-gradient(100deg, #8B78FF 0%, #52E0EE 100%);
  --sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth;
       /* the sticky bar covers whatever an anchor scrolls to, on every
          page — not just the ones that snap */
       scroll-padding-top: var(--head-h); }
body {
  margin: 0; background: var(--void); color: var(--ink);
  font: 400 1.02rem/1.72 var(--sans);
}
.shell { max-width: 100rem; margin: 0 auto; padding: 0 1.3rem; }  /* 1600px — matches myhealthcare.com */
.narrow { max-width: 100rem; }
a { color: var(--vio-hi); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--cyan); }
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; border-radius: 3px; }
::selection { background: rgba(139,120,255,.35); }

/* ── chrome ─────────────────────────────────────────────────────────────── */
.skip {
  position: absolute; left: -9999px; top: 0; width: 1px; height: 1px;
  overflow: hidden;
}
.skip:focus {
  position: fixed; left: .6rem; top: .6rem; width: auto; height: auto;
  z-index: 30; padding: .6rem .9rem; border-radius: 9px;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--cyan); box-shadow: 0 6px 24px rgba(0,0,0,.5);
  font: 500 .78rem/1 var(--mono); letter-spacing: .08em;
}
.site-head {
  position: sticky; top: 0; z-index: 10;
  background: rgba(10,14,26,.82); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.site-head .shell {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: .4rem 1rem; padding-top: .8rem; padding-bottom: .8rem;
}
.wordmark {
  display: inline-flex; align-items: center; gap: .55rem;
  font: 700 .92rem/1 var(--sans); letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink); text-decoration: none;
}
.wm-sub { color: var(--muted); font-weight: 500; letter-spacing: .08em; text-transform: none; }
.wordmark:hover { color: var(--ink); }
.wordmark:hover .spark { filter: drop-shadow(0 0 6px var(--cyan)); }
.spark { width: 22px; height: 22px; fill: var(--cyan); stroke: var(--vio); stroke-width: 1; }
.site-nav { display: flex; gap: 1.2rem; flex-wrap: wrap; }
.site-nav a {
  font: 500 .74rem/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); text-decoration: none; padding: .3rem 0;
}
.site-nav a:hover { color: var(--cyan); }
.site-nav a.here { color: var(--ink); box-shadow: 0 2px 0 0 var(--cyan); }

.site-foot { border-top: 1px solid var(--line); margin-top: 5.5rem; }
.site-foot .shell { padding-top: 3rem; padding-bottom: 2rem; }
.site-foot p { margin: .35rem 0; color: var(--muted); font-size: .92rem; }

/* Column footer — brand block at ~2x a link column, then FOUR equal link
   columns under mono labels, then a thin bottom rule. The map's two
   sub-columns are tracks of this grid rather than a nested split, which is
   what keeps every link column the same width and every gutter the same
   size; one --foot-gap drives both levels. Same shape as the other sites in
   the family; the palette and the label type are this one's. */
.foot-grid {
  --foot-gap: 2.4rem;
  display: grid; grid-template-columns: 2fr repeat(4, 1fr);
  gap: var(--foot-gap); padding-bottom: 2.4rem;
}
.foot-brand .wordmark { margin-bottom: .95rem; }
.foot-brand p { margin: 0; max-width: 34rem; }
.foot-col h3 {
  font: 500 .68rem/1 var(--mono); letter-spacing: .18em;
  text-transform: uppercase; color: var(--cyan); margin: 0 0 .9rem;
}
.foot-col ul { list-style: none; margin: 0; padding: 0; }
.foot-col li a {
  display: block; padding: .22rem 0; font-size: .92rem;
  color: var(--muted); text-decoration: none;
}
.foot-col li a:hover { color: var(--cyan); }
/* the sections run DOWN two sub-columns, so reading order survives the split.
   It spans two tracks and repeats the parent gutter, so its columns line up
   with Start here and This site instead of being half their width. */
.foot-map { grid-column: span 2; display: grid; grid-template-columns: 1fr 1fr;
            gap: 0 var(--foot-gap); align-content: start; }
.foot-map h3 { grid-column: 1 / -1; }

.foot-bottom {
  border-top: 1px solid var(--line); padding-top: 1.3rem;
  display: flex; flex-wrap: wrap; gap: .5rem 2rem;
  align-items: center; justify-content: space-between;
  font: 400 .74rem/1.6 var(--mono); letter-spacing: .04em; color: var(--muted);
}
.foot-bottom a { color: var(--muted); }
.foot-bottom a:hover { color: var(--cyan); }

@media (max-width: 1080px) {
  /* two columns: the brand and the (already two-wide) map each take the full
     row, so Start here and This site pair up instead of leaving a hole */
  .foot-grid { --foot-gap: 2rem; grid-template-columns: 1fr 1fr; }
  .foot-brand, .foot-map { grid-column: 1 / -1; }
}
@media (max-width: 620px) {
  .foot-grid { --foot-gap: 1.9rem; grid-template-columns: 1fr; }
  .foot-map { grid-template-columns: 1fr 1fr; }
}

/* ── type ───────────────────────────────────────────────────────────────── */
h1 {
  font: 800 clamp(2.1rem, 5vw, 3.3rem)/1.1 var(--sans);
  letter-spacing: -.025em; margin: .5rem 0 1rem;
}
.grad {
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
h2 { font: 700 1.28rem/1.35 var(--sans); letter-spacing: -.01em; margin: 2.2rem 0 .55rem; }
.sys-tag {
  font: 500 .72rem/1.5 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted); margin: 2.2rem 0 0;
}
.sys-tag a { color: inherit; text-decoration: none; }
.sys-tag a:hover { color: var(--cyan); }
.dek { font-size: 1.14rem; line-height: 1.65; color: var(--muted); margin: 0 0 1.5rem; }
p { margin: .85rem 0; }
li { margin: .3rem 0; }

pre {
  background: #0B1122; border: 1px solid var(--line); color: #C9D8EE;
  border-radius: 10px; padding: 1rem 1.15rem; overflow-x: auto;
  font: .85rem/1.62 var(--mono); margin: 1.2rem 0;
}
code { font-family: var(--mono); font-size: .92em; }
p code, li code {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 5px; padding: .08em .35em; font-size: .85em; color: #C9D8EE;
}
.plain-list { list-style: none; padding: 0; }
.plain-list li { margin: .55rem 0; color: var(--muted); }

/* ── hero ───────────────────────────────────────────────────────────────── */
.hero { position: relative; overflow: hidden; border-bottom: 1px solid var(--line); }
.hero canvas.bg {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
}
.hero::after {   /* vignette so text always wins */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse at 30% 40%, rgba(10,14,26,.15), rgba(10,14,26,.86) 78%);
}
.hero .shell { position: relative; z-index: 1; padding: 5.5rem 1.3rem 4.5rem; }
.hero .dek { max-width: none; }
.hero-cta { margin-top: 1.8rem; display: flex; gap: .8rem; flex-wrap: wrap; }
.btn {
  display: inline-block; padding: .62rem 1.15rem; border-radius: 9px;
  font: 600 .85rem/1 var(--sans); letter-spacing: .02em; text-decoration: none;
  background: var(--grad); color: #0A0E1A;
  transition: transform .18s ease, box-shadow .18s ease;
}
.btn:hover { color: #0A0E1A; transform: translateY(-2px); box-shadow: 0 6px 24px rgba(82,224,238,.35); }
.btn.ghost {
  background: transparent; color: var(--ink); border: 1px solid var(--line);
}
.btn.ghost:hover { border-color: var(--cyan); color: var(--cyan); box-shadow: none; }

/* ── home rows ──────────────────────────────────────────────────────────── */
.row-title { display: flex; flex-direction: column; gap: .35rem; margin-top: 4rem; }
.row-title .sys-tag { margin: 0; }
.row-note { color: var(--muted); max-width: none; margin-top: .4rem; }

.path { display: grid; gap: 1.1rem; margin-top: 1.8rem;
        grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); }
.path-card {
  grid-row: span 1; display: flex; align-items: center; gap: 1rem;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  padding: 1.05rem 1.2rem; text-decoration: none; position: relative; overflow: hidden;
  transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.path-card::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--grad);
  opacity: .65; transition: opacity .2s ease;
}
.path-card:hover {
  transform: translateY(-3px); border-color: #34426E;
  box-shadow: 0 10px 34px rgba(0,0,0,.45), 0 0 0 1px rgba(139,120,255,.15);
}
.path-card:hover::before { opacity: 1; }
.path-num { font: 700 1.5rem/1 var(--mono); color: var(--vio); min-width: 2.4rem; }
.path-body { display: flex; flex-direction: column; gap: .15rem; }
.path-name { font: 700 1.08rem/1.3 var(--sans); color: var(--ink); }
.path-dek { color: var(--muted); font-size: .9rem; }
.path-count { margin-left: auto; font: 500 .7rem/1 var(--mono); letter-spacing: .1em;
              color: var(--muted); white-space: nowrap; }
.path-toc { list-style: none; margin: .5rem 0 1rem; padding: 0 .4rem; }
.path-toc li { margin: .34rem 0; font-size: .93rem; }
.path-toc a { color: var(--muted); text-decoration: none; }
.path-toc a:hover { color: var(--cyan); }
.path-toc a::before { content: "▸ "; color: var(--vio); }

/* roadmap */
.roadmap { list-style: none; display: flex; flex-wrap: wrap; gap: .6rem .8rem;
           margin: 1.6rem 0 0; padding: 0; }
.rm {
  display: inline-flex; align-items: center; gap: .5rem;
  border: 1px solid var(--line); border-radius: 999px; padding: .42rem .95rem;
  font: 500 .8rem/1 var(--mono); letter-spacing: .04em; color: var(--muted);
}
.rm .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line); }
.rm.live { color: var(--ink); border-color: #2C5E66; }
.rm.live .dot { background: var(--cyan); box-shadow: 0 0 8px var(--cyan); }
.rm.training { border-color: #3A3670; }
.rm.training .dot { background: var(--vio); animation: pulse 2.2s ease-in-out infinite; }
@keyframes pulse { 0%,100% { box-shadow: 0 0 0 0 rgba(139,120,255,.55); }
                   50%      { box-shadow: 0 0 0 6px rgba(139,120,255,0); } }
.about { padding-bottom: 1rem; }

/* ── viz panels ─────────────────────────────────────────────────────────── */
.viz-panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  margin: 2rem 0 2.4rem; overflow: hidden;
}
.viz-panel canvas { display: block; width: 100%; height: 300px; }
@media (min-width: 1200px) {           /* wide screens: the viz owns the room */
  .viz-panel canvas { height: min(560px, 70vh); }
}
@media (min-width: 1560px) {           /* full 1600px frame: double height */
  .viz-panel canvas { height: min(720px, 75vh); }
}
.viz-cap {
  margin: 0; padding: .6rem 1rem .7rem; border-top: 1px solid var(--line);
  font: 500 .74rem/1.5 var(--mono); letter-spacing: .08em; color: var(--muted);
}
.viz-cap::before { content: "● "; color: var(--cyan); animation: blink 2.4s ease-in-out infinite; }
@keyframes blink { 50% { opacity: .25; } }

/* ── panel controls: expand + sound ───────────────────────────────────────
   These live in the caption row rather than floating over the canvas. An
   absolutely positioned overlay would sit on top of whatever the viz draws
   in that corner, and armreach's ground rule spans the full width at
   exactly that height. In the row they also survive fullscreen, where the
   exit control has to stay reachable. Built by viz.js at runtime, so a
   reader with JS off is never handed a control that does nothing. */
.viz-cap { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .7rem; }
.viz-cap::before { flex: 0 0 auto; }
.cap-txt { flex: 1 1 16rem; min-width: 0; }
.viz-ctl { display: flex; gap: .4rem; flex: 0 0 auto; margin-left: auto; }
.viz-btn {
  background: var(--panel); color: var(--muted);
  /* --line is 1.4:1 and is for decorative rules only; an interactive
     border needs 3:1 against its background (WCAG 1.4.11) */
  border: 1px solid var(--ctl); border-radius: 8px;
  padding: .32rem .62rem; cursor: pointer;
  font: 600 .64rem/1 var(--mono); letter-spacing: .11em; text-transform: uppercase;
}
.viz-btn:hover { border-color: var(--cyan); color: var(--cyan); }
.viz-btn[aria-pressed="true"] {
  border-color: var(--vio); color: var(--vio-hi); box-shadow: inset 0 0 0 1px var(--vio);
}

/* Fullscreen. Deliberately six rules and not two selector lists: one
   unsupported selector invalidates an entire list, and pairing :fullscreen
   with :-webkit-full-screen would take the canvas sizing down with it in
   whichever browser lacks the other — the same trap documented in the snap
   block below. .vz-max is the fallback for iPhone Safari, which still
   refuses fullscreen on anything that is not a <video>. */
.viz-panel:fullscreen { margin: 0; border: 0; border-radius: 0;
  background: var(--void); display: flex; flex-direction: column; }
.viz-panel:-webkit-full-screen { margin: 0; border: 0; border-radius: 0;
  background: var(--void); display: flex; flex-direction: column; }
.viz-panel.vz-max { position: fixed; inset: 0; z-index: 120;
  margin: 0; border: 0; border-radius: 0;
  background: var(--void); display: flex; flex-direction: column; }
.viz-panel:fullscreen canvas { flex: 1 1 0; height: 0 !important; min-height: 0; }
.viz-panel:-webkit-full-screen canvas { flex: 1 1 0; height: 0 !important; min-height: 0; }
.viz-panel.vz-max canvas { flex: 1 1 0; height: 0 !important; min-height: 0; }
html.vz-locked, html.vz-locked body { overflow: hidden; }

/* ── hubs / entries ─────────────────────────────────────────────────────── */
.card-head { max-width: none; }
.entries { list-style: none; margin: 1rem 0 0; padding: 0; counter-reset: n; }
.entry { border-top: 1px solid var(--line); }
.entry:last-child { border-bottom: 1px solid var(--line); }
.entry-link {
  display: grid; grid-template-columns: 3.2rem 1fr auto; align-items: baseline;
  gap: .25rem 1.1rem; padding: 1rem .3rem; text-decoration: none;
  transition: background .15s ease;
}
.entry-min {
  font: 500 .7rem/1 var(--mono); letter-spacing: .1em; color: var(--muted);
  white-space: nowrap;
}
.entry-link:hover { background: rgba(139,120,255,.05); }
.entry-link::before {
  counter-increment: n; content: counter(n, decimal-leading-zero);
  font: 600 .8rem/1 var(--mono); color: var(--vio);
}
.entry-title { font: 700 1.15rem/1.35 var(--sans); color: var(--ink); }
.entry-link:hover .entry-title { color: var(--cyan); }
.entry-hook { grid-column: 2; color: var(--muted); font-size: .93rem; }
.entry-pair {
  display: block; padding: 0 .3rem .9rem 4.3rem; margin-top: -.5rem;
  font: 500 .72rem/1 var(--mono); letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.entry-pair a { color: var(--cyan); text-decoration: none; }
.entry-pair a:hover { text-decoration: underline; }

/* ── articles ───────────────────────────────────────────────────────────── */
article { padding-top: .6rem; }
.figure { margin: 1.6rem auto; max-width: 75rem; }  /* images stay ≤1200px, centered in the wide frame */
.figure img {
  width: 100%; height: auto; border-radius: 12px; border: 1px solid var(--line);
  display: block;
}
.slot {
  position: relative; border: 1px solid var(--line); border-radius: 12px;
  aspect-ratio: 1792 / 700; overflow: hidden;
  background:
    radial-gradient(circle at 20% 35%, rgba(139,120,255,.12), transparent 45%),
    radial-gradient(circle at 75% 65%, rgba(82,224,238,.10), transparent 45%),
    var(--panel);
}
.slot-field {
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(151,160,188,.28) 1px, transparent 1.4px);
  background-size: 26px 26px;
  mask-image: linear-gradient(120deg, transparent 20%, #000 50%, transparent 80%);
  -webkit-mask-image: linear-gradient(120deg, transparent 20%, #000 50%, transparent 80%);
  animation: scan 5.5s linear infinite;
}
@keyframes scan { from { mask-position: -60% 0; -webkit-mask-position: -60% 0; }
                  to   { mask-position: 160% 0; -webkit-mask-position: 160% 0; } }
.slot-tag {
  position: absolute; left: .9rem; bottom: .7rem; margin: 0;
  font: 500 .72rem/1 var(--mono); letter-spacing: .12em; color: var(--muted);
}
.hero-art { display: none; }  /* hero uses the live field canvas instead */

.adjacent {
  display: flex; justify-content: space-between; gap: 1rem;
  border-top: 1px solid var(--line); margin-top: 3rem; padding-top: 1.3rem;
}
.adj { text-decoration: none; max-width: 46%; font: 700 1rem/1.4 var(--sans); color: var(--ink); }
.adj span { display: block; font: 500 .68rem/1 var(--mono); letter-spacing: .14em;
            text-transform: uppercase; color: var(--muted); margin-bottom: .35rem; }
.adj:hover { color: var(--cyan); }
.adj.next { text-align: right; margin-left: auto; }
.notfound { padding-top: 3.5rem; }

/* ── motion: scroll reveals ─────────────────────────────────────────────── */
.reveal { opacity: 0; transform: translateY(18px);
          transition: opacity .6s ease, transform .6s ease; }
.reveal.in { opacity: 1; transform: none; }

/* ── the lab ────────────────────────────────────────────────────────────── */
.site-nav a.start-nav { color: var(--vio-hi); }
.site-nav a.start-nav::before { content: "→ "; }
.site-nav a.start-nav.here { color: var(--vio-hi); box-shadow: 0 2px 0 0 var(--vio); }
.site-nav a.lab-nav { color: var(--cyan); }
.site-nav a.lab-nav::before { content: "◆ "; font-size: .85em; }
.site-nav a.lab-nav.here { color: var(--cyan); box-shadow: 0 2px 0 0 var(--vio); }
.site-nav.many { gap: .9rem; }
.site-nav.many a { font-size: .68rem; letter-spacing: .1em; }

.lab { margin: 1.6rem 0 2.6rem; }
.lab-controls {
  display: flex; flex-wrap: wrap; gap: .7rem 1.1rem; align-items: flex-end;
  margin: .9rem 0 .4rem;
}
.lab-ctl {
  display: flex; flex-direction: column; gap: .32rem;
  font: 500 .66rem/1 var(--mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
.lab-ctl-val { color: var(--cyan); letter-spacing: .05em; text-transform: none; }
.lab-ctl input[type="range"] { width: 9.5rem; accent-color: var(--vio); margin: 0; }
.lab-ctl select {
  background: var(--panel); color: var(--ink); border: 1px solid var(--ctl);
  border-radius: 7px; padding: .38rem .5rem; font: 500 .8rem var(--mono);
}
.lab-btn {
  background: var(--panel); color: var(--ink); border: 1px solid var(--ctl);
  border-radius: 8px; padding: .5rem .85rem; cursor: pointer;
  font: 600 .72rem/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
}
.lab-btn:hover { border-color: var(--cyan); color: var(--cyan); }
.lab-btn.primary { background: var(--grad); color: #0A0E1A; border-color: transparent; }
.lab-btn.primary:hover { color: #0A0E1A; box-shadow: 0 4px 18px rgba(82,224,238,.3); }
.lab-btn.toggle.on { border-color: var(--vio); color: var(--vio-hi);
                     box-shadow: inset 0 0 0 1px var(--vio); }
.lab-stage {
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  overflow: hidden; margin: .9rem 0; height: 340px;
}
@media (min-width: 1200px) {
  /* --tall is set per-instrument by lab.js; !important beats the inline
     narrow-screen height */
  .lab-stage { height: min(var(--tall, 680px), 80vh) !important; }
}
.lab-stage canvas { display: block; width: 100%; height: 100%; touch-action: none;
                    cursor: crosshair; }
.lab-read { font-size: .88rem; line-height: 1.6; color: var(--muted); margin: .5rem 0 0; }
.lab-field-name {
  font: 500 .66rem/1.5 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); margin: 1.2rem 0 .45rem;
}
.lab-ta, .lab-in {
  width: 100%; background: #0B1122; border: 1px solid var(--ctl); color: var(--ink);
  border-radius: 10px; padding: .7rem .85rem; font: .88rem/1.55 var(--mono);
  resize: vertical;
}
.lab-ta:focus, .lab-in:focus { outline: 2px solid var(--cyan); outline-offset: 1px; }
.lab-chips { display: flex; flex-wrap: wrap; gap: .35rem .28rem; align-items: center;
             margin: .9rem 0; min-height: 2rem; }
.lab-chip { border: 1px solid; border-radius: 6px; padding: .18rem .42rem;
            font: 500 .84rem var(--mono); background: rgba(11,17,34,.85);
            white-space: pre; }
.lab-chip-gap { width: .35rem; }
.lab-mergelog { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .5rem; }
.lab-merge { font: 500 .72rem var(--mono); color: var(--muted);
             border: 1px solid var(--line); border-radius: 6px; padding: .16rem .42rem; }
.lab-out {
  background: #0B1122; border: 1px solid var(--line); border-radius: 10px;
  padding: .9rem 1rem; font: .88rem/1.7 var(--mono); color: #C9D8EE;
  min-height: 7.5rem; white-space: pre-wrap; overflow-wrap: break-word;
  margin: .9rem 0 0;
}
.lab-verdict {
  margin: 1.1rem 0 .2rem; padding: .7rem .9rem; border-radius: 9px;
  font: 500 .9rem/1.5 var(--mono); border: 1px solid var(--line);
}
.lab-verdict.ok { color: var(--cyan); border-color: #2C5E66; }
.lab-verdict.bad { color: var(--vio-hi); border-color: #3A3670; }
.lab-verdict.warn { color: #FFC46B; border-color: #5C4A28; }
.lab-chunks { margin-bottom: .6rem; }
.lab-why { color: var(--muted); font: 500 .82rem/1.6 var(--mono); margin: .6rem 0; }
.lab-chunk {
  display: block; border: 1px solid var(--line); border-radius: 9px;
  padding: .6rem .8rem; margin: .5rem 0; background: rgba(11,17,34,.6);
}
.lab-chunk.has { border-color: #2C5E66; background: rgba(82,224,238,.06); }
.lab-chunk .rk {
  display: block; font: 500 .7rem/1.6 var(--mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); margin-bottom: .25rem;
}
.lab-chunk.has .rk { color: var(--cyan); }
.lab-chunk .tx { color: #C9D8EE; font: .86rem/1.6 var(--mono); }

.lab-noscript {
  border: 1px solid var(--line); border-radius: 10px; padding: .9rem 1rem;
  color: var(--muted); font: 500 .85rem/1.6 var(--mono);
}
.lab .lab-in { margin-top: .9rem; }

/* lab cards (home teaser) */
.lab-grid { display: grid; gap: 1rem; margin-top: 1.7rem;
            grid-template-columns: repeat(auto-fit, minmax(16.5rem, 1fr)); }
.lab-card {
  display: flex; flex-direction: column; gap: .3rem;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  padding: 1rem 1.1rem; text-decoration: none;
  transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.lab-card:hover { transform: translateY(-3px); border-color: #2C5E66;
                  box-shadow: 0 10px 30px rgba(0,0,0,.4), 0 0 0 1px rgba(82,224,238,.14); }
.lab-card .tag { font: 500 .62rem/1 var(--mono); letter-spacing: .16em;
                 text-transform: uppercase; color: var(--cyan); }
.lab-card .ttl { font: 700 1.02rem/1.3 var(--sans); color: var(--ink); }
.lab-card .hk { color: var(--muted); font-size: .88rem; }

/* ── index (/suchen/) & changelog ───────────────────────────────────────── */
.idx-filter { margin: .4rem 0 0; max-width: 30rem; }
.idx-sec h2 {
  font: 500 .72rem/1.5 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--cyan); margin: 2rem 0 .4rem;
}
.idx ul { list-style: none; margin: 0; padding: 0; }
.idx li { margin: .3rem 0; display: flex; gap: .6rem; align-items: baseline;
          flex-wrap: wrap; }
.idx a { color: var(--ink); text-decoration: none; font-weight: 600; }
.idx a:hover { color: var(--cyan); }
.idx .hk { color: var(--muted); font-size: .88rem; }
.idx-none { color: var(--muted); font: 500 .85rem var(--mono); margin-top: 1.5rem; }
/* self-check questions on section hubs */
.checks { margin-top: 3.5rem; max-width: 58rem; }
.check {
  border-top: 1px solid var(--line); padding: .1rem 0;
}
.check:last-of-type { border-bottom: 1px solid var(--line); }
.check summary {
  cursor: pointer; list-style: none; padding: .95rem 2rem .95rem 0;
  font: 600 1.02rem/1.5 var(--sans); color: var(--ink); position: relative;
}
.check summary::-webkit-details-marker { display: none; }
.check summary::after {
  content: "+"; position: absolute; right: .3rem; top: .8rem;
  font: 400 1.35rem/1 var(--mono); color: var(--vio);
}
.check[open] summary::after { content: "−"; }
.check summary:hover { color: var(--cyan); }
.check p {
  margin: 0 0 1.1rem; color: var(--muted); font-size: .95rem; max-width: 46rem;
}

/* reading paths (/start/) */
.path-route { margin-top: 3rem; }
.proute { list-style: none; counter-reset: pr; margin: 1.2rem 0 0; padding: 0; }
.pstep {
  counter-increment: pr; display: grid; grid-template-columns: 2.6rem 1fr;
  gap: .2rem .9rem; padding: .7rem 0; border-top: 1px solid var(--line);
}
.pstep:last-child { border-bottom: 1px solid var(--line); }
.pstep::before {
  content: counter(pr, decimal-leading-zero);
  font: 600 .8rem/1.7 var(--mono); color: var(--vio);
}
.pstep a { font: 700 1.02rem/1.5 var(--sans); color: var(--ink); text-decoration: none; }
.pstep a:hover { color: var(--cyan); }
.pstep .why { grid-column: 2; color: var(--muted); font-size: .92rem; }

.glossary { list-style: none; margin: 1.6rem 0 0; padding: 0; }
.glossary .gl {
  display: grid; grid-template-columns: 15rem 1fr; gap: .3rem 1.4rem;
  align-items: baseline; padding: .7rem 0; border-top: 1px solid var(--line);
}
.glossary .gl:last-child { border-bottom: 1px solid var(--line); }
.gl-term { font: 700 .98rem/1.4 var(--sans); color: var(--ink); text-decoration: none; }
.gl-term:hover { color: var(--cyan); }
.gl-def { color: var(--muted); font-size: .93rem; line-height: 1.6; }
@media (max-width: 720px) {
  .glossary .gl { grid-template-columns: 1fr; }
}
.changelog .cl { margin: 2.2rem 0; }
.changelog .cl .sys-tag { margin: 0; }
.changelog .cl h2 { margin: .3rem 0 .4rem; }
.changelog .cl p { color: var(--muted); margin: 0; }

/* "try it in the lab" callouts inside articles */
.try-lab {
  display: block; border: 1px solid var(--line); border-radius: 10px;
  padding: .72rem .95rem; margin: 1.5rem 0; text-decoration: none;
  font: 600 .74rem/1.5 var(--mono); letter-spacing: .08em; text-transform: uppercase;
  color: var(--cyan);
}
.try-lab::before { content: "◆ lab · "; color: var(--muted); }
.try-lab:hover { border-color: var(--cyan); }

/* ── about / the author ─────────────────────────────────────────────────── */
/* The portrait is the only photograph of a person on the site, so it gets the
   one identity accent — a gradient hairline — rather than a new treatment.
   It lives in static/ and NOT static/img/: that directory is the article
   image-slot pipeline, and a file there inflates build.py's "images present"
   count and can be picked up as a page's og:image at the wrong dimensions. */
.bio-head {
  display: grid; grid-template-columns: 17rem 1fr; gap: 1.4rem 2.6rem;
  align-items: start; margin: 2.2rem 0 1rem;
}
.bio-shot { margin: 0; position: sticky; top: calc(var(--head-h) + 1.5rem); }
.bio-frame {
  padding: 1px; border-radius: 15px; background: var(--grad);
  box-shadow: 0 14px 40px rgba(0,0,0,.5);
}
.bio-frame img {
  display: block; width: 100%; height: auto; border-radius: 14px;
}
.bio-cap {
  margin-top: .9rem; font: 500 .72rem/1.7 var(--mono);
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.bio-cap b { display: block; color: var(--ink); letter-spacing: .06em; }
.bio-intro > :first-child { margin-top: 0; }

/* dated list of things he has put on the public web */
.bio-sites { list-style: none; margin: 1.2rem 0 0; padding: 0; }
.bio-sites li {
  display: grid; grid-template-columns: 4.2rem 1fr; gap: .2rem .9rem;
  align-items: baseline; padding: .55rem 0; border-top: 1px solid var(--line);
}
.bio-sites li:last-child { border-bottom: 1px solid var(--line); }
.bio-sites .yr { font: 600 .8rem/1.7 var(--mono); color: var(--vio); }
.bio-sites .what { grid-column: 2; color: var(--muted); font-size: .92rem; }

/* contact row — same pill as the roadmap, different job */
.bio-links { list-style: none; display: flex; flex-wrap: wrap;
             gap: .6rem .8rem; margin: 1.4rem 0 0; padding: 0; }
.bio-links a {
  display: inline-flex; align-items: center; gap: .5rem;
  border: 1px solid var(--line); border-radius: 999px; padding: .42rem 1rem;
  font: 500 .8rem/1 var(--mono); letter-spacing: .04em;
  color: var(--muted); text-decoration: none;
}
.bio-links a:hover { color: var(--cyan); border-color: #2C5E66; }

@media (max-width: 860px) {
  .bio-head { grid-template-columns: 1fr; gap: 1.2rem; }
  .bio-shot { position: static; max-width: 15rem; }
  /* linkedin.com/in/kevin-luzbetak is the longest pill: ~279px against
     278px of room inside .shell at 320px. Tighten it rather than let it
     wrap, and give it leading in case it still does. */
  .bio-links a { padding: .42rem .75rem; letter-spacing: .02em;
                 line-height: 1.35; }
}

/* ── scroll stops on instrument pages ───────────────────────────────────────
   Only pages carrying a live canvas opt in: build.py sets html.snap when the
   body holds a .viz-panel or a [data-lab]. The sizing and the stop are gated
   separately, because they carry different risks.

   Both are inside `screen` (svh resolves against the page box when printing,
   so a section would otherwise claim most of a sheet, and canvases print
   blank) and inside no-preference (reduced-motion readers keep the plain
   layout) and inside min-height: 700px (on a short window a full-viewport
   section is mostly controls, and the reader needs to rest part-way through
   it). The sticky bar is measured, not assumed — see --head-h above. */
@media screen and (prefers-reduced-motion: no-preference) and (min-height: 700px) {
  /* an instrument IS the page, so it takes the whole screen */
  html.snap .lab:has(.lab-stage) {
    min-height: calc(100vh - var(--head-h));
    min-height: calc(100svh - var(--head-h));
    display: flex; flex-direction: column;
  }
  /* A hub's visualization is its portrait; the entry list underneath is the
     point of the page. Stopping short of the full screen keeps the first rows
     above the fold, so the stop never reads as a dead end. */
  html.snap .viz-panel {
    min-height: calc((100vh - var(--head-h)) * 0.8);
    min-height: calc((100svh - var(--head-h)) * 0.8);
    display: flex; flex-direction: column;
    margin: 1.4rem 0 1.1rem;
  }
  /* lab.js builds the instrument at runtime, so :has() cannot match until
     47KB of deferred script has run. Reserve most of the height up front, or
     everything below the instrument jumps once it does. */
  html.snap .lab { min-height: calc((100svh - var(--head-h)) * 0.7); }
  /* two instruments nest their controls and stage one level deeper */
  html.snap .lab-wrap {
    display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
  }

  /* The canvas absorbs whatever the controls and readouts leave. flex-basis
     must be 0, not auto: viz.js sets width/height ATTRIBUTES on the canvas
     from its measured box, giving it an intrinsic aspect ratio, and an auto
     basis then sizes the box from that ratio — a measure/layout loop that
     quietly ignores min-height. A zero basis takes the free space, nothing
     more. Kept as two rules on purpose: one unsupported selector invalidates
     a whole selector list, so pairing these would take the .viz-panel canvas
     down with :has() in a browser that lacks it. */
  html.snap .viz-panel canvas {
    flex: 1 1 0; height: 0 !important; min-height: 15rem;
  }
  html.snap .lab:has(.lab-stage) .lab-stage {
    flex: 1 1 0; height: 0 !important; min-height: 15rem;
  }
}

/* The stop itself needs one more gate. WebKit bug 243582 — open since 2022 —
   disables momentum scrolling outright whenever scroll snap is active,
   proximity included, so on a touch device every flick through the prose
   below would stop dead on release. Snap is a desktop-pointer affordance;
   touch readers keep the sizing above and scroll normally. */
@media screen and (pointer: fine) and (prefers-reduced-motion: no-preference)
   and (min-height: 700px) {
  html.snap { scroll-snap-type: y proximity; }
  /* The top of the page has to be a resting place too. Without a snap target
     at zero, the browser snaps the instrument up over the title the instant
     the page loads, and the reader never sees what they opened. */
  html.snap main { scroll-snap-align: start; }
  html.snap .viz-panel { scroll-snap-align: start; }
  html.snap .lab:has(.lab-stage) { scroll-snap-align: start; }
  /* Keyboard focus outranks snapping. Tabbing to a link just below a snap
     target scrolls it barely into view, snap pulls back, and the focused
     element ends up off-screen — WCAG 2.2 SC 2.4.11. The class is toggled by
     the header script rather than :has(), so it works everywhere. */
  html.snap.kb-focus { scroll-snap-type: none; }
}

/* ── quality floor ──────────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .hero .shell { padding-top: 3.5rem; padding-bottom: 3rem; }
  .viz-panel canvas { height: 240px; }
  .path-count { display: none; }
  .lab-stage { height: 300px !important; }
  .lab-ctl input[type="range"] { width: 7.5rem; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .slot-field, .rm.training .dot, .viz-cap::before { animation: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .btn, .path-card, .entry-link { transition: none; }
}

@media print { .viz-ctl { display: none; } }
