/* IOVI design system v7. Editorial document meshed with otl.network patterns, dynamic components,
   manifesto chapters and entry veil. Ultramarine is exactly #1f3aff in both modes, used sparingly. */
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(fonts/ibm-plex-mono-latin-400-normal.woff2) format('woff2');}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(fonts/ibm-plex-mono-latin-500-normal.woff2) format('woff2');}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url(fonts/ibm-plex-mono-latin-600-normal.woff2) format('woff2');}
*{margin:0;padding:0;box-sizing:border-box;} html{scroll-behavior:smooth;}
:root{--bg:#dee3ea;--paper:#e9edf2;--fg:#14171c;--mut:#55606e;--sig:#1f3aff;--onsig:#e9edf2;--line:#14171c;--hair:rgba(20,23,28,.17);}
[data-theme="dark"]{--bg:#14161a;--paper:#1b1e23;--fg:#e9ebee;--mut:#9aa1ab;--sig:#1f3aff;--onsig:#eff1f3;--line:#e9ebee;--hair:rgba(233,235,238,.16);}
body{font-family:var(--fam-display);background:var(--bg);color:var(--fg);line-height:1.5;-webkit-font-smoothing:antialiased;transition:background .3s ease,color .3s ease;min-height:100vh;}

/* corner-bracket frame */
.frame{position:fixed;inset:16px;pointer-events:none;z-index:30;}
.frame i{position:absolute;width:18px;height:18px;border:1.5px solid var(--line);}
.frame .tl{top:0;left:0;border-right:none;border-bottom:none;}
.frame .tr{top:0;right:0;border-left:none;border-bottom:none;}
.frame .bl{bottom:0;left:0;border-right:none;border-top:none;}
.frame .br{bottom:0;right:0;border-left:none;border-top:none;}

/* sticky top bar */
.topbar{position:sticky;top:0;z-index:20;display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap;padding:18px 44px;background:var(--bg);border-bottom:1.5px solid var(--line);transition:background .3s ease;}
.tb-mark{display:flex;align-items:center;line-height:0;text-decoration:none;}
.tb-mark svg{height:22px;width:auto;}
.tb-mark .lk-light{display:block;} .tb-mark .lk-dark{display:none;}
[data-theme="dark"] .tb-mark .lk-light{display:none;} [data-theme="dark"] .tb-mark .lk-dark{display:block;}
.tb-right{display:flex;align-items:center;gap:26px;flex-wrap:wrap;}
.tb-nav{display:flex;gap:22px;flex-wrap:wrap;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.14em;text-transform:uppercase;}
.tb-nav a{color:var(--mut);text-decoration:none;padding:2px 0;border-bottom:1.5px solid transparent;}
.tb-nav a:hover{color:var(--fg);}
.tb-nav a[aria-current="page"]{color:var(--fg);font-weight:600;border-bottom-color:var(--line);}
.toggle{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--mut);background:transparent;border:1.5px solid var(--hair);border-radius:999px;padding:8px 14px;cursor:pointer;}
.toggle:hover{color:var(--fg);border-color:var(--line);}
@media(max-width:860px){.topbar{padding:14px 22px;}.tb-right{gap:14px;}.tb-nav{gap:14px;}}

.doc{max-width:1080px;margin:0 auto;padding:0 44px 72px;}
@media(max-width:640px){.doc{padding:0 24px 56px;}}

/* hero + generative canvas */
.hero{text-align:center;padding:64px 0 0;position:relative;}
.hero-canvas{position:absolute;left:50%;top:-20px;transform:translateX(-50%);width:min(1000px,100vw);height:500px;pointer-events:none;z-index:-1;}
@media(prefers-reduced-motion:reduce){.hero-canvas{display:none;}}
.hero-art{margin:0 auto 30px;}
.hero-art svg{height:84px;width:auto;display:block;margin:0 auto;}
.hero-art .ink{stroke:var(--fg);}
.hero-art .soft{stroke:var(--mut);opacity:.55;}
.hero-art .flow{animation:flowdash 9s linear infinite;}
@keyframes flowdash{to{stroke-dashoffset:-64;}}
.hero-art .draw{opacity:0;animation:settle .7s cubic-bezier(.2,.7,.2,1) forwards;}
.hero-art .d2{animation-delay:.2s;}
@keyframes settle{from{opacity:0;transform:translateY(9px);}to{opacity:1;transform:none;}}
.kicker{font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.28em;text-transform:uppercase;color:var(--mut);}
.hero h1{font-weight:700;letter-spacing:-.03em;line-height:1.04;font-size:clamp(34px,5vw,58px);max-width:30ch;margin:20px auto 0;}
.hero-lede{font-family:'IBM Plex Mono',monospace;font-size:13px;line-height:1.75;color:var(--mut);max-width:80ch;margin:24px auto 0;}
.hero-lede.full{margin-top:14px;}
.hero.inner{padding-top:56px;}
.hero.inner h1{font-size:clamp(30px,4.2vw,46px);}
.hero .kicker,.hero .themes,.hero h1,.hero .hero-lede,.hero .joinwrap,.hero .joinnote{opacity:0;animation:fadeup .55s cubic-bezier(.2,.7,.2,1) forwards;}
.hero .kicker{animation-delay:.25s;}
.hero .themes{animation-delay:.35s;}
.hero h1{animation-delay:.45s;}
.hero .hero-lede{animation-delay:.6s;}
.hero .joinwrap{animation-delay:.75s;}
.hero .joinnote{animation-delay:.85s;}
@keyframes fadeup{from{opacity:0;transform:translateY(12px);}to{opacity:1;transform:none;}}
@media(prefers-reduced-motion:reduce){
.hero-art .flow{animation:none;}
.hero-art .draw{animation:none;opacity:1;}
.hero .kicker,.hero .themes,.hero h1,.hero .hero-lede,.hero .joinwrap,.hero .joinnote{animation:none;opacity:1;}
}

/* rotating themes */
.themes{position:relative;height:18px;margin-top:16px;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--mut);}
.themes span{position:absolute;left:0;right:0;top:0;opacity:0;transform:translateY(7px);transition:opacity .5s cubic-bezier(.2,.7,.2,1),transform .5s cubic-bezier(.2,.7,.2,1);}
.themes span.on{opacity:1;transform:none;}

/* thesis callout */
.callout{border-left:1.5px solid var(--line);padding:6px 0 6px 26px;margin-top:34px;font-size:20px;font-weight:500;letter-spacing:-.01em;line-height:1.45;max-width:56ch;}

/* partners strip */
.partners{margin-top:64px;text-align:center;}
.pn-cap{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.22em;text-transform:uppercase;color:var(--mut);margin-bottom:22px;}
.pl-marquee{overflow:hidden;}
.pl-track{display:flex;align-items:baseline;gap:56px;width:max-content;animation:tick 55s linear infinite reverse;}
.pl-marquee:hover .pl-track,.pl-track.paused{animation-play-state:paused;}
.plogo{color:var(--mut);opacity:.65;white-space:nowrap;transition:opacity .25s ease,color .25s ease;cursor:default;}
.plogo:hover{opacity:1;color:var(--fg);}
@keyframes tick{to{transform:translateX(-50%);}}
@media(prefers-reduced-motion:reduce){.pl-track{animation:none;flex-wrap:wrap;width:auto;justify-content:center;}.pl-ctl{display:none;}}

/* primary action */
.joinwrap{margin-top:40px;text-align:center;}
.joinbtn{display:inline-block;background:var(--sig);color:var(--onsig);font-family:'IBM Plex Mono',monospace;font-weight:600;font-size:13px;letter-spacing:.06em;text-transform:uppercase;padding:20px 46px;border-radius:8px;text-decoration:none;border:1.5px solid var(--sig);cursor:pointer;}
.joinbtn:hover{opacity:.92;}
.joinbtn.sm{padding:13px 26px;font-size:11px;}
.note{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--mut);line-height:1.6;margin-top:14px;}
.joinnote{text-align:center;margin-top:16px;}

/* page section sub-nav */
.body-grid{display:grid;grid-template-columns:190px 1fr;gap:0 56px;align-items:start;}
.pagenav{position:sticky;top:96px;display:flex;flex-direction:column;gap:13px;font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.16em;text-transform:uppercase;padding-top:96px;}
.pagenav .pn-h{color:var(--mut);letter-spacing:.2em;border-bottom:1.5px solid var(--hair);padding-bottom:10px;margin-bottom:2px;}
.pagenav a{color:var(--mut);text-decoration:none;display:flex;gap:10px;align-items:center;transition:color .25s ease;}
.pagenav a::before{content:"";flex:0 0 6px;height:6px;border-radius:50%;background:var(--hair);transition:background .25s ease;}
.pagenav a:hover{color:var(--fg);}
.pagenav a.on{color:var(--fg);font-weight:600;}
.pagenav a.on::before{background:var(--sig);}
.body-main{min-width:0;}
.body-main .sec:first-child{margin-top:56px;}
@media(max-width:900px){
.body-grid{grid-template-columns:1fr;}
.pagenav{position:static;flex-direction:row;flex-wrap:nowrap;overflow-x:auto;gap:22px;padding:14px 0;margin-top:40px;border-top:1.5px solid var(--line);border-bottom:1.5px solid var(--line);}
.pagenav .pn-h{display:none;}
.pagenav a{white-space:nowrap;}
}

/* numbered sections */
.sec{margin-top:96px;scroll-margin-top:96px;}
.sec-head{display:flex;align-items:baseline;gap:10px;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.16em;text-transform:uppercase;padding-top:16px;margin-bottom:34px;position:relative;}
.sec-head::before{content:"";position:absolute;top:0;left:0;right:0;height:1.5px;background:linear-gradient(90deg,var(--line) 0%,var(--line) 55%,transparent 100%);}
.sec-head .n{color:var(--sig);font-weight:600;}
.sec-head .sl{color:var(--mut);}
.sec-head b,.sec-head h2{color:var(--fg);font-weight:600;}
.sec-head .tag{margin-left:auto;color:var(--mut);letter-spacing:.1em;}
.anch{opacity:0;margin-left:2px;color:var(--mut);text-decoration:none;transition:opacity .2s ease;}
.sec-head:hover .anch{opacity:1;}
.anch:hover{color:var(--fg);}
@media(max-width:640px){.sec{margin-top:64px;}.sec-head .tag{display:none;}}

/* two-column editorial split */
.cols{display:grid;grid-template-columns:1fr 1fr;gap:0 72px;position:relative;}
.cols::before{content:"";position:absolute;left:50%;top:4px;bottom:4px;border-left:1px solid var(--hair);}
.cols .cl{padding-right:8px;}
.cols .cr{color:var(--mut);}
.cols p{font-size:15px;line-height:1.7;margin:0 0 16px;}
.cols p:last-child{margin-bottom:0;}
.cols .cr p{font-size:14px;line-height:1.7;}
.cols strong{font-weight:600;color:var(--fg);}
.cols .cr strong{color:var(--mut);}
@media(max-width:760px){.cols{grid-template-columns:1fr;gap:22px 0;}.cols::before{display:none;}.cols .cl{padding-right:0;}}

/* prose fallback */
.prose{font-size:15px;line-height:1.7;max-width:64ch;}
.prose p{margin:0 0 16px;} .prose p:last-child{margin-bottom:0;}

/* card grids */
.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:36px;}
.cards.two{grid-template-columns:repeat(2,1fr);}
@media(max-width:820px){.cards,.cards.two{grid-template-columns:1fr;}}
.card{display:block;border:1.5px solid var(--hair);border-radius:12px;background:var(--paper);padding:26px 24px 28px;text-decoration:none;color:inherit;transition:border-color .2s ease,transform .2s ease,box-shadow .2s ease;}
a.card:hover{border-color:var(--line);transform:translateY(-4px);box-shadow:0 12px 30px rgba(22,19,13,.09);}
[data-theme="dark"] a.card:hover{box-shadow:0 12px 30px rgba(0,0,0,.35);}
.card .ic{height:24px;margin-bottom:18px;}
.card .ic svg{height:24px;width:auto;display:block;}
.card .ic .ink{stroke:var(--fg);} .card .ic .node{fill:var(--fg);}
.card .tag{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--sig);margin-bottom:10px;}
.card h3{font-size:17px;font-weight:700;letter-spacing:-.01em;margin-bottom:10px;}
.card p{font-size:13.5px;line-height:1.65;color:var(--mut);}
.reveal .card{opacity:0;transform:translateY(12px);transition:opacity .45s cubic-bezier(.2,.7,.2,1),transform .45s cubic-bezier(.2,.7,.2,1),border-color .2s ease,box-shadow .2s ease;}
.reveal.vis .card{opacity:1;transform:none;}
.reveal.vis .card:nth-child(2){transition-delay:.08s;}
.reveal.vis .card:nth-child(3){transition-delay:.16s;}
.reveal.vis .card:nth-child(4){transition-delay:.24s;}
.reveal.vis .card:nth-child(5){transition-delay:.32s;}
.reveal.vis .card:nth-child(6){transition-delay:.4s;}
.reveal.vis a.card:hover{transition-delay:0s;transform:translateY(-4px);}
@media(prefers-reduced-motion:reduce){.reveal .card{opacity:1;transform:none;transition:none;}}

/* interactive stack */
.stack{display:grid;grid-template-columns:270px 1fr;gap:28px;margin-top:34px;align-items:stretch;}
.stack-layers{display:flex;flex-direction:column;gap:10px;}
.layer{text-align:left;background:var(--paper);border:1.5px solid var(--hair);border-radius:10px;padding:12px 16px;cursor:pointer;font-family:'IBM Plex Mono',monospace;letter-spacing:.12em;text-transform:uppercase;font-size:10px;color:var(--mut);transition:border-color .25s ease;}
.layer b{display:block;font-family:var(--fam-display);text-transform:none;letter-spacing:-.01em;font-size:15px;font-weight:700;color:var(--fg);margin-top:2px;}
.layer:hover,.layer.active{border-color:var(--line);}
.layer.active{animation:blip .45s cubic-bezier(.2,.7,.2,1);}
@keyframes blip{0%{box-shadow:0 0 0 0 var(--hair);}60%{box-shadow:0 0 0 5px var(--hair);}100%{box-shadow:0 0 0 0 rgba(0,0,0,0);}}
.stack-detail{border:1.5px solid var(--hair);border-radius:12px;background:var(--paper);padding:26px;}
.stack-detail .sd{display:none;}
.stack-detail .sd.on{display:block;animation:fadeup .32s cubic-bezier(.2,.7,.2,1);}
.stack-detail .sd-tag{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);margin-bottom:8px;}
.stack-detail .sd-name{font-weight:700;font-size:19px;letter-spacing:-.01em;margin-bottom:10px;}
.stack-detail .sd-desc{font-size:14px;line-height:1.65;color:var(--mut);max-width:52ch;}
.stack-detail .sd-wgs{margin-top:18px;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.1em;text-transform:uppercase;}
.stack-detail .sd-wgs a{color:var(--fg);text-decoration:none;border-bottom:1.5px solid var(--line);margin-right:14px;padding-bottom:1px;}
.stack-detail .sd-wgs a:hover{opacity:.75;}
@media(max-width:760px){.stack{grid-template-columns:1fr;}}
@media(prefers-reduced-motion:reduce){.layer.active{animation:none;}.stack-detail .sd.on{animation:none;}}

/* expertise list */
.exp-h{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);margin-bottom:8px;}
.exp{list-style:none;font-family:'IBM Plex Mono',monospace;font-size:11.5px;line-height:2.1;letter-spacing:.05em;color:var(--mut);}
.exp li::before{content:"+ ";color:var(--fg);}

/* skill finder */
.skills{display:flex;flex-wrap:wrap;gap:10px;margin-top:22px;}
.skills.center{justify-content:center;}
.sk{font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.05em;border:1.5px solid var(--hair);border-radius:999px;padding:9px 16px;background:var(--paper);color:var(--mut);cursor:pointer;transition:border-color .2s ease,color .2s ease,background .2s ease;}
.sk:hover{border-color:var(--line);color:var(--fg);}
.sk.sel{background:var(--fg);color:var(--bg);border-color:var(--fg);}
.sk-reset{background:none;border:none;font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--mut);border-bottom:1.5px solid var(--hair);cursor:pointer;margin-top:18px;padding:0 0 2px;display:none;}
.sk-reset.on{display:inline-block;}
.sk-reset:hover{color:var(--fg);border-color:var(--line);}
.yours{display:none;font-family:'IBM Plex Mono',monospace;font-size:9px;letter-spacing:.12em;text-transform:uppercase;border:1.5px solid var(--sig);color:var(--sig);border-radius:999px;padding:3px 10px;margin-left:12px;white-space:nowrap;vertical-align:middle;}

/* track browser */
.trackgrid{display:grid;grid-template-columns:240px 1fr;gap:28px;align-items:start;margin-top:8px;}
.track-rail{display:flex;flex-direction:column;gap:8px;position:sticky;top:96px;}
.tr-item{display:flex;align-items:center;gap:10px;text-align:left;background:var(--paper);border:1.5px solid var(--hair);border-radius:10px;padding:13px 16px;cursor:pointer;font-family:var(--fam-display);font-size:14px;font-weight:600;color:var(--fg);transition:border-color .25s ease,opacity .3s ease;}
.tr-item .trn{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.1em;color:var(--mut);transition:color .25s ease;}
.tr-item:hover,.tr-item.active{border-color:var(--line);}
.tr-item.active{animation:blip .45s cubic-bezier(.2,.7,.2,1);}
.tr-item.active .trn{color:var(--sig);font-weight:600;}
.tr-item.match .trn{color:var(--sig);font-weight:600;}
.tr-item.match::after{content:"";width:6px;height:6px;border-radius:50%;background:var(--sig);margin-left:auto;}
.tr-item.dim{opacity:.45;}
.track-viewer{border:1.5px solid var(--hair);border-radius:12px;background:var(--paper);padding:28px;min-height:300px;}
.tp{display:none;}
.tp.on{display:block;animation:fadeup .32s cubic-bezier(.2,.7,.2,1);}
.tp-tag{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);margin-bottom:10px;}
.tp-name{font-size:20px;font-weight:700;letter-spacing:-.01em;margin-bottom:12px;}
.tp-desc{font-size:14.5px;line-height:1.65;color:var(--mut);max-width:58ch;margin-bottom:22px;}
.tp .exp{margin-bottom:6px;}
.tp-join{margin-top:24px;}
.tp-body p{font-size:14.5px;line-height:1.7;margin:0 0 14px;}
.tp-body p:last-child{margin-bottom:0;}
.tp-body p.mut{color:var(--mut);}
.tp-body strong{font-weight:600;}
.tp-next{background:none;border:none;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--fg);border-bottom:1.5px solid var(--line);cursor:pointer;margin-top:22px;padding:0 0 2px;}
.tp-next:hover{opacity:.7;}
@media(max-width:820px){
.trackgrid{grid-template-columns:1fr;}
.track-rail{position:static;flex-direction:row;flex-wrap:nowrap;overflow-x:auto;padding-bottom:6px;}
.tr-item{white-space:nowrap;}
}
@media(prefers-reduced-motion:reduce){.tr-item.active{animation:none;}.tp.on{animation:none;}}

/* architecture figure */
.archfig{margin-top:26px;}
.archfig svg{width:100%;max-width:680px;height:auto;display:block;}
.as-box{fill:var(--paper);stroke:var(--hair);stroke-width:1.5;}
.as-box.emph{stroke:var(--line);}
.as-wgbox{fill:var(--bg);stroke:var(--hair);stroke-width:1.5;}
.as-name{font-family:var(--fam-display);font-weight:700;font-size:14px;fill:var(--fg);}
.as-l{font-family:'IBM Plex Mono',monospace;font-size:9px;letter-spacing:.1em;fill:var(--mut);}
.as-wg{font-family:'IBM Plex Mono',monospace;font-size:9.5px;letter-spacing:.08em;fill:var(--fg);}
.as-flow{stroke:var(--mut);stroke-width:1;stroke-dasharray:3 5;}
.as-arrow{stroke:var(--fg);stroke-width:1.2;}
.as-tip{fill:var(--fg);}
.figcap{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--mut);margin-top:14px;}
.reveal .as-anim{opacity:0;transition:opacity .5s cubic-bezier(.2,.7,.2,1);}
.reveal.vis .as-anim{opacity:1;}
.reveal.vis .as-anim:nth-of-type(2){transition-delay:.08s;}
.reveal.vis .as-anim:nth-of-type(3){transition-delay:.16s;}
.reveal.vis .as-anim:nth-of-type(4){transition-delay:.24s;}
.reveal.vis .as-anim:nth-of-type(5){transition-delay:.32s;}
@media(prefers-reduced-motion:reduce){.reveal .as-anim{opacity:1;transition:none;}}

/* terminal card */
.term{background:#14161a;border-radius:10px;padding:20px 22px;font-family:'IBM Plex Mono',monospace;font-size:12px;line-height:2;color:#e9ebee;max-width:420px;}
.term .tp1{color:#1f3aff;font-weight:600;}
.term .tl2{color:#9aa1ab;padding-left:16px;}

/* steps */
.steps .stn{font-family:'IBM Plex Mono',monospace;font-size:12px;font-weight:600;letter-spacing:.1em;color:var(--sig);margin-bottom:14px;}
.steps .card p a{color:inherit;}

/* swatches (design page) */
.sw{display:inline-block;width:14px;height:14px;border-radius:4px;border:1.5px solid var(--hair);vertical-align:-2px;margin-right:10px;}
.type-sample{border:1.5px solid var(--hair);border-radius:12px;background:var(--paper);padding:24px;margin-top:16px;}
.type-sample .ts-cap{font-family:'IBM Plex Mono',monospace;font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);margin-bottom:10px;}

/* fielded record table */
.record{border-top:1.5px solid var(--line);}
.record .r{display:flex;gap:24px;border-bottom:1.5px solid var(--line);padding:13px 0;}
.record .k{font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--mut);flex:0 0 150px;}
.record .v{font-family:'IBM Plex Mono',monospace;font-size:12.5px;color:var(--fg);flex:1;min-width:0;line-height:1.5;}
@media(max-width:560px){.record .r{flex-wrap:wrap;gap:4px 24px;}.record .k{flex-basis:100%;}}

/* FAQ accordion */
.faq{border-top:1.5px solid var(--line);}
.fq{border-bottom:1.5px solid var(--line);}
.fq summary{list-style:none;cursor:pointer;display:flex;align-items:baseline;gap:14px;padding:18px 0;font-weight:600;font-size:16px;letter-spacing:-.01em;}
.fq summary::-webkit-details-marker{display:none;}
.fq summary::after{content:"+";margin-left:auto;font-family:'IBM Plex Mono',monospace;font-size:15px;color:var(--mut);display:inline-block;transition:transform .25s ease,color .25s ease;}
.fq[open] summary::after{transform:rotate(45deg);color:var(--sig);}
.fq summary:hover::after{color:var(--fg);}
.fq .fq-a{padding:0 0 20px;max-width:70ch;}
.fq .fq-a p{font-size:14.5px;line-height:1.7;color:var(--mut);margin:0 0 12px;}
.fq .fq-a p:last-child{margin-bottom:0;}
.fq .fq-a a{color:inherit;}
@media(prefers-reduced-motion:reduce){.fq summary::after{transition:none;}}

/* blog cards (Medium feed) */
.bloggrid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:36px;}
@media(max-width:820px){.bloggrid{grid-template-columns:1fr;}}
.bcard .bc-img{height:150px;border-radius:8px;background-size:cover;background-position:center;background-color:var(--bg);margin-bottom:16px;border:1.5px solid var(--hair);}
.blog-empty{grid-column:1/-1;border:1.5px dashed var(--hair);border-radius:12px;padding:44px 24px;text-align:center;font-family:'IBM Plex Mono',monospace;font-size:12px;line-height:1.8;color:var(--mut);}
.blog-empty a{color:var(--fg);}

/* manifesto chapters */
.mchap{display:grid;grid-template-columns:1fr 230px;gap:24px 60px;align-items:start;}
.mch-body p{font-size:15.5px;line-height:1.75;margin:0 0 18px;max-width:60ch;}
.mch-body p:last-child{margin-bottom:0;}
.mch-body strong{font-weight:600;}
.mch-fig{margin:6px 0 0;color:var(--fg);}
.mch-fig svg{width:100%;max-width:220px;height:auto;display:block;opacity:.9;}
.mch-fig figcaption{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--mut);margin-top:12px;}
@media(max-width:760px){.mchap{grid-template-columns:1fr;}.mch-fig{max-width:190px;}}

/* entry veil: typed founding narrative */
.introveil{position:fixed;inset:0;z-index:80;background:#14161a;display:none;align-items:center;justify-content:center;padding:32px;opacity:1;transition:opacity .8s ease;}
.introveil.on{display:flex;}
.introveil.out{opacity:0;pointer-events:none;}
.iv-inner{max-width:64ch;text-align:center;}
.iv-type{font-family:'IBM Plex Mono',monospace;font-size:clamp(15px,2vw,19px);line-height:1.9;color:#e9ebee;min-height:5.7em;}
.iv-type::after{content:"_";color:#1f3aff;animation:ivblink 1s steps(1) infinite;}
.iv-type.done::after{content:"";}
@keyframes ivblink{50%{opacity:0;}}
.iv-line{font-family:'IBM Plex Mono',monospace;font-size:clamp(12px,1.5vw,14px);line-height:1.9;color:#9aa1ab;margin-top:28px;opacity:0;transform:translateY(8px);transition:opacity .7s ease,transform .7s ease;}
.iv-line.on{opacity:1;transform:none;}
.iv-skip{position:fixed;bottom:26px;right:30px;background:none;border:1.5px solid rgba(233,235,238,.3);border-radius:999px;color:#9aa1ab;font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;padding:9px 16px;cursor:pointer;}
.iv-skip:hover{color:#e9ebee;border-color:#e9ebee;}

/* modal */
.modal{position:fixed;inset:0;z-index:50;display:none;align-items:center;justify-content:center;padding:20px;background:rgba(11,10,7,.5);backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px);}
.modal.open{display:flex;}
.modal-card{display:flex;flex-direction:column;width:min(700px,94vw);height:min(90vh,900px);background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 24px 70px rgba(0,0,0,.4);}
.modal-head{display:flex;justify-content:space-between;align-items:center;padding:15px 20px;border-bottom:1px solid #e6e2d8;font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:#16130d;}
.modal-close{background:none;border:none;font-size:22px;line-height:1;color:#6b6457;cursor:pointer;padding:0 4px;}
.modal-close:hover{color:#16130d;}
.gform{flex:1;width:100%;min-height:0;border:0;background:#fff;}
.modal-foot{padding:10px 16px;text-align:center;font-family:'IBM Plex Mono',monospace;font-size:11px;color:#6b6457;border-top:1px solid #e6e2d8;}
.modal-foot a{color:#1f3aff;text-decoration:none;}
.modal-foot a:hover{text-decoration:underline;}

/* agent chat shell (parked: markup removed from pages, styles kept for reactivation) */
.chatbtn{position:fixed;bottom:24px;right:24px;z-index:44;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.12em;text-transform:uppercase;background:var(--paper);color:var(--fg);border:1.5px solid var(--line);border-radius:999px;padding:12px 20px;cursor:pointer;}
.chatbtn:hover{background:var(--bg);}
.chat{position:fixed;bottom:78px;right:24px;z-index:45;width:min(340px,calc(100vw - 48px));background:var(--paper);border:1.5px solid var(--line);border-radius:12px;display:none;flex-direction:column;overflow:hidden;box-shadow:0 18px 50px rgba(0,0,0,.18);}
.chat.open{display:flex;}
.chat-head{display:flex;justify-content:space-between;align-items:center;padding:12px 14px;border-bottom:1.5px solid var(--hair);font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);}
.chat-head button{background:none;border:none;color:var(--mut);font-size:18px;cursor:pointer;line-height:1;}
.chat-head button:hover{color:var(--fg);}
.chat-msgs{padding:14px;display:flex;flex-direction:column;gap:10px;max-height:280px;overflow-y:auto;}
.msg{font-size:13px;line-height:1.55;padding:10px 12px;border-radius:10px;max-width:92%;}
.msg.bot{background:var(--bg);border:1.5px solid var(--hair);color:var(--fg);align-self:flex-start;}
.msg.bot a{color:inherit;}
.msg.me{background:var(--fg);color:var(--bg);align-self:flex-end;}
.chat-in{display:flex;border-top:1.5px solid var(--hair);}
.chat-in input{flex:1;border:none;background:transparent;padding:12px 14px;font-family:var(--fam-display);font-size:13px;color:var(--fg);outline:none;}
.chat-in input::placeholder{color:var(--mut);}
.chat-in button{border:none;background:transparent;color:var(--fg);font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:0 14px;cursor:pointer;}

/* colophon footer */
footer{border-top:1.5px solid var(--line);margin-top:96px;padding:24px 0 0;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:14px;}
footer .fl{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--mut);letter-spacing:.04em;}
footer .stamp{color:var(--mut);}
footer .fr{display:flex;align-items:center;gap:20px;flex-wrap:wrap;}
footer .fr a{font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--mut);text-decoration:none;display:flex;align-items:center;}
footer .fr a:hover{color:var(--fg);}

/* scroll reveal */
.reveal{opacity:0;transform:translateY(14px);transition:opacity .38s cubic-bezier(.2,.7,.2,1),transform .38s cubic-bezier(.2,.7,.2,1);}
.reveal.vis{opacity:1;transform:none;}
@media(prefers-reduced-motion:reduce){.reveal{opacity:1;transform:none;transition:none;}}

/* ============ v3 redesign additions (v10) ============ */

/* numbered left index rail (Paradigm-style) */
.railgrid{grid-template-columns:230px 1fr;}
.railgrid .pagenav{gap:11px;padding-top:64px;}
.railgrid .pagenav a{font-size:10px;letter-spacing:.13em;}
.railgrid .pagenav a::before{display:none;}
.railgrid .pagenav .rn{color:var(--mut);font-weight:400;margin-right:9px;transition:color .25s ease;}
.railgrid .pagenav a.on .rn{color:var(--sig);font-weight:600;}
@media(max-width:900px){.railgrid{grid-template-columns:1fr;}.railgrid .pagenav .rn{margin-right:5px;}}

/* proof strip */
.proof{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:36px;}
@media(max-width:820px){.proof{grid-template-columns:repeat(2,1fr);}}
.pf{border:1.5px solid var(--hair);border-radius:12px;background:var(--paper);padding:22px;text-decoration:none;color:inherit;display:block;transition:border-color .2s ease;}
a.pf:hover{border-color:var(--line);}
.pf .n{font-size:34px;font-weight:700;letter-spacing:-.02em;line-height:1;}
.pf .d{font-family:'IBM Plex Mono',monospace;font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--mut);margin-top:10px;line-height:1.7;}

/* interstitial epigraphs */
.epi{font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.24em;text-transform:uppercase;color:var(--mut);text-align:center;margin:112px 0 -34px;}

/* redirect stubs */
.stub{min-height:70vh;display:flex;align-items:center;justify-content:center;text-align:center;font-family:'IBM Plex Mono',monospace;font-size:13px;line-height:2;color:var(--mut);}
.stub a{color:inherit;}

/* pinned scroll-build stack */
.pinwrap{height:220vh;}
.pinstage{position:sticky;top:88px;display:flex;flex-direction:column;justify-content:flex-start;gap:44px;padding-top:20px;}
.pinstage .sec-head{width:100%;margin-bottom:0;}
.sbuild{display:grid;grid-template-columns:300px 1fr;gap:48px;width:100%;align-items:center;}
.sb-col{display:flex;flex-direction:column;gap:10px;}
.sb-layer{background:var(--paper);border:1.5px solid var(--hair);border-radius:10px;padding:13px 18px;font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--mut);opacity:0;transform:translateY(26px);will-change:transform,opacity;}
.sb-layer b{display:block;font-family:var(--fam-display);text-transform:none;letter-spacing:-.01em;font-size:16px;font-weight:700;color:var(--fg);margin-top:2px;}
.sb-layer.done{border-color:var(--line);}
.sb-note{display:none;}
.sb-note.on{display:block;animation:fadeup .3s cubic-bezier(.2,.7,.2,1);}
.sb-tag{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);margin-bottom:10px;}
.sb-desc{font-size:16px;line-height:1.7;color:var(--fg);max-width:46ch;}
.sb-wgs{margin-top:20px;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.1em;text-transform:uppercase;}
.sb-wgs a{color:var(--fg);text-decoration:none;border-bottom:1.5px solid var(--line);margin-right:14px;padding-bottom:1px;}
.sb-wgs a:hover{opacity:.75;}
@media(max-width:760px){.sbuild{grid-template-columns:1fr;gap:26px;}.pinstage{align-items:flex-start;padding-top:20px;}}
@media(prefers-reduced-motion:reduce){
.pinwrap{height:auto;}
.pinstage{position:static;height:auto;}
.sb-layer{opacity:1;transform:none;}
.sb-note{display:block;margin-bottom:20px;}
}

/* ============ v9/v10: dark cinematic + brutalist + living document ============ */

/* the scene engine owns all entrances: neutralize the old reveal + view() systems */
.reveal,.reveal .card{opacity:1;transform:none;}
.reveal .card{transition:border-color .2s ease,box-shadow .2s ease;}
@supports (animation-timeline: view()){
@media (prefers-reduced-motion: no-preference){
.proof .pf,.mch-fig svg{animation:none;}
}}

/* crosshair register marks per section */
.sec{position:relative;}
.sec::after{content:"+";position:absolute;top:6px;right:-2px;font-family:'IBM Plex Mono',monospace;font-size:12px;color:var(--mut);opacity:.5;}

/* brutalist scale */
.sec{margin-top:56px;}
.sec-head{align-items:baseline;gap:16px;margin-bottom:34px;padding-top:20px;}
.sec-head b,.sec-head h2{font-family:var(--fam-display);text-transform:none;letter-spacing:-.025em;font-size:clamp(27px,3.4vw,46px);line-height:1.05;font-weight:700;}
.sec-head .n{font-size:12px;}
.hero{padding-top:88px;}
.hero h1{font-size:clamp(40px,6.4vw,86px);line-height:1.0;max-width:22ch;}
.hero-lede{font-size:14px;}
.mch-body p{font-size:16.5px;line-height:1.8;}
@media(max-width:640px){.sec{margin-top:48px;}}

/* The hero used to sit in front of a soft radial bloom in dark mode. It was the
   last blurred glow on the site after the closing panel lost its own, and it is the
   most template-recognisable device in the whole system, so it is gone. The heroes
   sit on flat canvas like every other surface. */

/* ============ v10: every section is a pinned build scene ============ */
.scene .scn-wrap{height:160vh;}
.scene .scn-stage{position:sticky;top:88px;padding-bottom:8px;}
.scn-u{opacity:0;transform:translateY(30px);will-change:transform,opacity;}
@media(max-width:760px),(prefers-reduced-motion:reduce){
.scene .scn-wrap{height:auto!important;}
.scene .scn-stage{position:static;min-height:0;}
.scn-u{opacity:1;transform:none;}
}

/* kinetic hero headline: words rise after the veil; one outlined word */
.hero h1{text-wrap:balance;}
.hero h1 .hw{display:inline-block;opacity:0;transform:translateY(.35em);}
html.hero-go .hero h1 .hw{animation:hwin .6s cubic-bezier(.2,.7,.2,1) forwards;}
html.hero-go .hero h1 .hw:nth-child(1){animation-delay:.05s;}
html.hero-go .hero h1 .hw:nth-child(2){animation-delay:.14s;}
html.hero-go .hero h1 .hw:nth-child(3){animation-delay:.23s;}
html.hero-go .hero h1 .hw:nth-child(4){animation-delay:.32s;}
html.hero-go .hero h1 .hw:nth-child(5){animation-delay:.41s;}
@keyframes hwin{to{opacity:1;transform:none;}}
.hero h1 .ol{color:transparent;-webkit-text-stroke:2px var(--fg);text-stroke:2px var(--fg);}
.hero{will-change:transform,opacity;}
@media(prefers-reduced-motion:reduce){
.hero h1 .hw{opacity:1;transform:none;animation:none!important;}
}
/* neutralize the v7 h1 fade so words own the entrance */
html.hero-go .hero h1{opacity:1;animation:none;}

/* ============ v11: professional layout pass (grid, left alignment, rhythm) ============ */

/* left-aligned editorial hero (Paradigm x Linear) */
.hero{text-align:left;padding:96px 0 0;}
.hero-art{margin:0 0 32px;}
.hero-art svg{margin:0;height:40px;}
.hero-art .soft{display:none;}
.themes{text-align:left;}
.themes span{left:0;right:auto;}
.hero h1{margin:20px 0 0;max-width:15ch;font-size:clamp(46px,7.2vw,96px);letter-spacing:-.035em;}
.hero-lede{font-family:var(--fam-display);font-size:19px;line-height:1.55;color:var(--fg);margin:32px 0 0;max-width:56ch;letter-spacing:0;}
.hero-lede.full{margin-top:14px;font-size:15.5px;color:var(--mut);line-height:1.65;}
.joinwrap{text-align:left;margin-top:40px;}
.joinnote{text-align:left;}
.partners{margin-top:96px;text-align:left;}
.pn-cap{text-align:left;}

/* grid discipline: consistent measure, aligned label column, 8px rhythm */
.doc{max-width:1240px;}
.body-grid{gap:0 64px;}
.railgrid{grid-template-columns:200px 1fr;}
.sec{margin-top:64px;}
.sec-head{margin-bottom:40px;}
.sec-head .n{display:inline-block;min-width:36px;}
.mchap{grid-template-columns:minmax(0,7fr) minmax(0,3fr);gap:24px 80px;}
.mch-body p{max-width:58ch;}
.callout{font-size:23px;max-width:44ch;}
.sb-desc{max-width:44ch;}
.hero.inner h1{font-size:clamp(34px,4.6vw,56px);}
@media(max-width:640px){.hero h1{font-size:clamp(38px,10vw,52px);}}

/* ============ v12: the ordering machine hero + blog tab ============ */
.hero.v3grid{display:grid;grid-template-columns:minmax(0,6fr) minmax(0,5fr);gap:64px;align-items:center;padding:72px 0 0;}
.hv-l .kicker{margin-bottom:6px;}
.hero.v3grid h1{font-size:clamp(52px,6.6vw,100px);max-width:9ch;margin:18px 0 0;}
.hero.v3grid .hero-lede{margin-top:26px;}
.hv-r{position:relative;}
#orderCanvas{width:100%;max-width:560px;aspect-ratio:1/1;display:block;margin:0 auto;}
.hv-cap{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mut);text-align:center;margin-top:10px;}
@media(max-width:900px){
.hero.v3grid{grid-template-columns:1fr;gap:40px;}
#orderCanvas{max-width:420px;}
}
html.hero-go .hero.v3grid .hw:nth-child(4){animation-delay:.32s;}

/* ============ v13: clean centered hero (OTL register) on slate ============ */
.hero.hero-c{text-align:center;padding:72px 0 0;display:block;}
.hero-c .hero-art{margin:0 auto 30px;}
.hero-c .hero-art svg{margin:0 auto;height:72px;}
.hero-c .hero-art .soft{display:block;}
.hero-c h1{margin:22px auto 0;max-width:26ch;font-size:clamp(34px,4.6vw,62px);letter-spacing:-.03em;line-height:1.12;}
.hero-c h1 .acc{font-family:'IBM Plex Mono',monospace;font-style:italic;font-weight:400;color:var(--mut);letter-spacing:-.02em;}
.hero-c .hero-lede{margin:24px auto 0;text-align:center;font-family:'IBM Plex Mono',monospace;font-size:13px;line-height:1.75;color:var(--mut);max-width:66ch;}
.hero-c .joinwrap{text-align:center;margin-top:36px;}
.hero-c .joinnote{text-align:center;}
.hero-c + .partners{margin-top:72px;text-align:center;}
.hero-c + .partners .pn-cap{text-align:center;}

/* sun / moon theme toggle */
.toggle{padding:8px 11px;line-height:0;display:inline-flex;align-items:center;}
.toggle .ic-sun{display:none;}
.toggle .ic-moon{display:block;}
[data-theme="dark"] .toggle .ic-moon{display:none;}
[data-theme="dark"] .toggle .ic-sun{display:block;}


/* ============ v14: audit remediation ============ */
html{scroll-padding-top:96px;}
/* small ultramarine text gets an accessible tint in dark mode only (buttons/wordmark keep exact #1f3aff) */
:root{--sig-text:#1f3aff;}
[data-theme="dark"]{--sig-text:#6e82ff;}
.sec-head .n,.railgrid .pagenav a.on .rn,.card .tag,.pf .tag,.steps .stn,.term .tp1{color:var(--sig-text);}
/* skip link */
.skip{position:fixed;top:-48px;left:16px;z-index:99;background:var(--fg);color:var(--bg);font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.1em;text-transform:uppercase;padding:10px 16px;border-radius:0 0 8px 8px;text-decoration:none;transition:top .2s ease;}
.skip:focus{top:0;}
/* visible focus everywhere */
:focus-visible{outline:2px solid var(--sig);outline-offset:3px;border-radius:2px;}
/* footer icon links: 24px minimum target */
footer .fr a{min-width:24px;min-height:24px;justify-content:center;}
/* mobile: section heads wrap instead of overflowing */
@media(max-width:640px){
.sec-head{flex-wrap:wrap;row-gap:4px;}
.sec-head b,.sec-head h2{font-size:clamp(21px,6.2vw,28px);min-width:0;overflow-wrap:anywhere;}
.anch{display:none;}
.blog-empty{padding:32px 14px;}
}
.sec-head h2{margin:0;}

/* mobile overflow: grid items must be allowed to shrink; clip any straggler at the root */
html,body{overflow-x:clip;}
@media(max-width:900px){
.railgrid{grid-template-columns:minmax(0,1fr);}
.body-grid{grid-template-columns:minmax(0,1fr);}
.pagenav{min-width:0;max-width:100%;}
}


/* stack scene plate caption */
.sb-col .figcap{margin-top:18px;}

/* ============ v15: schematic figures, proof sources, benchmark plate ============ */

/* WG track schematics */

/* proof tiles: hover reveals the source (verifiability as a gesture) */
.pf{position:relative;overflow:hidden;}
.pf .src{position:absolute;left:0;right:0;bottom:0;padding:9px 22px;font-family:'IBM Plex Mono',monospace;font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--mut);background:var(--paper);border-top:1.5px solid var(--hair);transform:translateY(101%);transition:transform .25s cubic-bezier(.2,.7,.2,1);}
.pf:hover .src,.pf:focus-visible .src,.pf:focus .src{transform:none;}
@media(prefers-reduced-motion:reduce){.pf .src{transition:none;}}

/* benchmark plate */
.bench{border:1.5px solid var(--hair);border-radius:12px;background:var(--paper);padding:30px 30px 24px;max-width:720px;}
.bn-title{font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--mut);margin-bottom:24px;}
.b-row{display:grid;grid-template-columns:170px 1fr 70px;gap:16px;align-items:center;margin-bottom:14px;}
.b-l{font-size:14px;font-weight:600;}
.b-track{height:14px;border:1.5px solid var(--hair);border-radius:4px;overflow:hidden;background:var(--bg);}
.b-fill{height:100%;background:var(--mut);opacity:.55;min-width:5px;}
.b-fill.sigb{background:var(--sig);opacity:1;}
.b-v{font-family:'IBM Plex Mono',monospace;font-size:12px;text-align:right;}
.bn-note{font-family:'IBM Plex Mono',monospace;font-size:10.5px;letter-spacing:.08em;color:var(--mut);margin-top:18px;line-height:1.7;}
.b-pending{margin-top:16px;padding:12px 16px;border:1.5px dashed var(--hair);border-radius:8px;font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--mut);}
@media(max-width:640px){.b-row{grid-template-columns:1fr;gap:6px;}.b-v{text-align:left;}}

/* ============ v16: typographic spec plates replace pictorial figures ============ */
.specb{border:1.5px solid var(--hair);border-radius:10px;background:var(--paper);padding:16px 18px 8px;font-family:'IBM Plex Mono',monospace;}
.sp-hd{font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--mut);padding-bottom:11px;border-bottom:1.5px solid var(--hair);}
.sp-r{display:flex;gap:14px;padding:9px 0;}
.sp-r+.sp-r{border-top:1px solid var(--hair);}
.sp-k{flex:0 0 84px;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);padding-top:2px;}
.sp-v{font-size:11.5px;letter-spacing:.02em;color:var(--fg);line-height:1.55;}
@media(max-width:760px){.mch-fig{max-width:360px;}}

/* ============ v17: Genzio-feel pass. Soft fade-ups, rounded depth, atmosphere ============ */

/* motion: fade-up reveals replace the scrubbed scene engine */
.rv{opacity:0;transform:translateY(28px);transition:opacity .8s cubic-bezier(.2,.7,.2,1),transform .8s cubic-bezier(.2,.7,.2,1);}
.rv.in{opacity:1;transform:none;}
.rv.in .card,.rv.in .pf,.rv.in .step,.rv.in .chl,.rv.in .fq{animation:rvup .7s cubic-bezier(.2,.7,.2,1) backwards;}
.rv.in .pf:nth-child(2),.rv.in .step:nth-child(2),.rv.in .card:nth-child(2){animation-delay:.08s;}
.rv.in .pf:nth-child(3),.rv.in .step:nth-child(3),.rv.in .card:nth-child(3){animation-delay:.16s;}
.rv.in .pf:nth-child(4){animation-delay:.24s;}
@keyframes rvup{from{opacity:0;transform:translateY(22px);}to{opacity:1;transform:none;}}
@media(prefers-reduced-motion:reduce){
.rv{opacity:1;transform:none;transition:none;}
.rv.in .card,.rv.in .pf,.rv.in .step,.rv.in .chl,.rv.in .fq{animation:none;}
}

/* hero atmosphere: slow-drifting ultramarine wash, light-theme friendly */
.hero{position:relative;}
.atmo{position:absolute;inset:-120px -10vw 0;pointer-events:none;z-index:-1;overflow:visible;filter:blur(70px);}
.atmo i{position:absolute;border-radius:50%;display:block;}
.atmo .a1{width:520px;height:520px;left:8%;top:-60px;background:radial-gradient(closest-side,rgba(31,58,255,.16),transparent 70%);animation:drift1 19s ease-in-out infinite alternate;}
.atmo .a2{width:420px;height:420px;right:6%;top:40px;background:radial-gradient(closest-side,rgba(31,58,255,.10),transparent 70%);animation:drift2 23s ease-in-out infinite alternate;}
.atmo .a3{width:380px;height:380px;left:44%;top:180px;background:radial-gradient(closest-side,rgba(20,23,28,.07),transparent 70%);animation:drift1 27s ease-in-out infinite alternate-reverse;}
[data-theme="dark"] .atmo .a1{background:radial-gradient(closest-side,rgba(31,58,255,.22),transparent 70%);}
[data-theme="dark"] .atmo .a3{background:radial-gradient(closest-side,rgba(233,235,238,.05),transparent 70%);}
@keyframes drift1{from{transform:translate(0,0) scale(1);}to{transform:translate(70px,40px) scale(1.12);}}
@keyframes drift2{from{transform:translate(0,0) scale(1.05);}to{transform:translate(-60px,30px) scale(.95);}}
@media(prefers-reduced-motion:reduce){.atmo{display:none;}}

/* rounded surfaces with soft depth */
:root{--shadow:0 1px 2px rgba(20,23,28,.05),0 10px 30px rgba(20,23,28,.07);--shadow-h:0 2px 4px rgba(20,23,28,.06),0 16px 44px rgba(20,23,28,.11);}
[data-theme="dark"]{--shadow:0 1px 2px rgba(0,0,0,.3),0 12px 34px rgba(0,0,0,.35);--shadow-h:0 2px 4px rgba(0,0,0,.35),0 18px 48px rgba(0,0,0,.5);}
.card,.pf,.fq,.step,.chl,.stack,.record,.bench{border-radius:18px;border:1px solid var(--hair);background:var(--paper);box-shadow:var(--shadow);}
.card,.pf{transition:box-shadow .3s ease,transform .3s ease,border-color .3s ease;}
a.pf:hover,.card:hover{box-shadow:var(--shadow-h);transform:translateY(-3px);border-color:var(--hair);}
.pf{padding:28px;}
.pf .n{font-size:44px;}
.proof{gap:18px;}

/* process steps */
.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:40px;}
@media(max-width:820px){.steps{grid-template-columns:1fr;}}
.step{padding:30px 28px;}
.step .sn{font-family:'IBM Plex Mono',monospace;font-size:13px;color:var(--sig);letter-spacing:.08em;}
.step h3{font-size:21px;letter-spacing:-.015em;margin:14px 0 10px;}
.step p{font-size:14.5px;line-height:1.7;color:var(--mut);}

/* manifesto chapter list */
.chlist{margin-top:36px;display:flex;flex-direction:column;gap:12px;}
.chl{display:grid;grid-template-columns:44px minmax(0,220px) 1fr 30px;gap:18px;align-items:center;padding:20px 26px;text-decoration:none;color:inherit;transition:box-shadow .3s ease,transform .3s ease;}
.chl:hover{box-shadow:var(--shadow-h);transform:translateY(-2px);}
.chl .cn{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--sig);}
.chl b{font-size:16.5px;letter-spacing:-.01em;}
.chl .ct{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);}
.chl .ar{color:var(--mut);transition:transform .25s ease,color .25s ease;}
.chl:hover .ar{transform:translateX(4px);color:var(--fg);}
@media(max-width:700px){.chl{grid-template-columns:34px 1fr 24px;}.chl .ct{display:none;}}

/* FAQ accordion, rounded */
.faq{display:flex;flex-direction:column;gap:12px;margin-top:8px;}
.fq{padding:0;overflow:hidden;}
.fq summary{padding:22px 26px;font-size:16px;font-weight:600;letter-spacing:-.01em;cursor:pointer;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:18px;}
.fq summary::-webkit-details-marker{display:none;}
.fq summary::after{content:"+";font-family:'IBM Plex Mono',monospace;font-weight:400;font-size:18px;color:var(--mut);transition:transform .3s ease;}
.fq[open] summary::after{transform:rotate(45deg);}
.fq .fq-a{padding:0 26px 24px;}
.fq .fq-a p{font-size:14.5px;line-height:1.75;color:var(--mut);max-width:72ch;}

/* closing band */
/* The closing statement is part of the document, not a panel dropped into it: no
   gradient, no bloom, no inversion, and the same left edge as every section above.
   Those were the only gradient and the only blurred glow on the site, which is why
   the block read as imported from somewhere else. */
.closing{border-top:1.5px solid var(--line);padding:72px 0 40px;text-align:center;}
.closing h2{font-family:var(--fam-display);font-size:clamp(30px,4.2vw,52px);letter-spacing:-.03em;line-height:1.16;margin:0 auto;max-width:26ch;}
.closing .joinwrap{text-align:center;margin-top:46px;}

/* home flow: centered single column, generous rhythm */
.home-flow{max-width:1240px;margin:0 auto;}
.home-flow .sec{margin-top:120px;}
.home-flow .sec:first-child{margin-top:96px;}
@media(max-width:640px){.home-flow .sec{margin-top:80px;}}

/* stack panel padding now that it is a card */
.stack{padding:26px;margin-top:36px;}


/* ============ v18: inline manifesto accordion, comparison, big footer, per-element reveals ============ */

/* per-element reveals own all motion now; sections render immediately */
.rv{opacity:1;transform:none;transition:none;}
.rv.in .card,.rv.in .pf,.rv.in .step,.rv.in .chl,.rv.in .fq{animation:none;}
.ru{opacity:0;transform:translateY(24px);transition:opacity .65s cubic-bezier(.2,.7,.2,1),transform .65s cubic-bezier(.2,.7,.2,1);}
.ru.in{opacity:1;transform:none;}
@media(prefers-reduced-motion:reduce){.ru{opacity:1;transform:none;transition:none;}}

/* record + bench inside rounded cards: soft internal rules, breathing room */
.record{padding:6px 28px;}
.record .r{border-bottom:1px solid var(--hair);padding:16px 0;}
.record .r:last-child{border-bottom:none;}
.bench{padding:26px 28px;}
.b-row{border-bottom:none;}

/* mission: wider single column */
.home-flow .mch-body p{max-width:74ch;font-size:17px;}

/* top bar CTA */
.tb-cta{margin-left:4px;}
@media(max-width:640px){.tb-cta{display:none;}}

/* manifesto accordion */
.chx{border-radius:18px;border:1px solid var(--hair);background:var(--paper);box-shadow:var(--shadow);overflow:hidden;}
.chx summary{display:grid;grid-template-columns:44px minmax(0,220px) 1fr 30px;gap:18px;align-items:center;padding:22px 26px;cursor:pointer;list-style:none;}
.chx summary::-webkit-details-marker{display:none;}
.chx .cn{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--sig);}
.chx b{font-size:16.5px;letter-spacing:-.01em;}
.chx .ct{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);}
.chx .pl{font-family:'IBM Plex Mono',monospace;font-size:18px;color:var(--mut);transition:transform .3s ease;text-align:center;}
.chx[open] .pl{transform:rotate(45deg);}
.chx:hover{box-shadow:var(--shadow-h);}
.chx-b{padding:2px 26px 28px;max-width:76ch;}
.chx-b p{font-size:16px;line-height:1.8;margin-bottom:16px;}
.chx-b .record{margin-top:10px;}
.chx-b .joinwrap{text-align:left;margin-top:18px;}
@media(max-width:700px){.chx summary{grid-template-columns:34px 1fr 24px;}.chx .ct{display:none;}}

/* comparison */
.diff{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-top:40px;}
@media(max-width:820px){.diff{grid-template-columns:1fr;}}
.dcol{border-radius:20px;border:1px solid var(--hair);background:var(--paper);box-shadow:var(--shadow);padding:30px 30px 16px;}
.dcol.di{border-color:rgba(31,58,255,.35);box-shadow:var(--shadow),0 0 0 1px rgba(31,58,255,.18);}
.dh{font-family:var(--fam-display);font-weight:700;font-size:19px;letter-spacing:-.01em;margin-bottom:12px;}
.dcol.di .dh{color:var(--sig);}
.dr{font-size:14.5px;line-height:1.6;padding:13px 0 13px 26px;border-bottom:1px solid var(--hair);position:relative;color:var(--fg);}
.dcol .dr:last-child{border-bottom:none;}
.dr::before{position:absolute;left:0;font-family:'IBM Plex Mono',monospace;font-size:13px;}
.dcol.di .dr::before{content:"+";color:var(--sig);}
.dcol.do .dr::before{content:"\2013";color:var(--mut);}
.dcol.do .dr{color:var(--mut);}

/* big footer */
footer.bigfoot{margin-top:120px;border-top:1.5px solid var(--line);padding:56px 0 28px;display:block;}
.bf-grid{display:grid;grid-template-columns:minmax(0,1.6fr) repeat(3,minmax(0,1fr));gap:40px;}
@media(max-width:820px){.bf-grid{grid-template-columns:1fr 1fr;}}
@media(max-width:520px){.bf-grid{grid-template-columns:1fr;}}
.bf-mark{font-family:var(--fam-display);font-weight:700;font-size:20px;letter-spacing:-.01em;}
.bf-mark .v{color:var(--sig);}
.bf-brand p{font-family:'IBM Plex Mono',monospace;font-size:11px;line-height:1.8;color:var(--mut);margin-top:14px;max-width:34ch;}
.bf-h{font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--mut);margin-bottom:16px;}
.bf-col{display:flex;flex-direction:column;gap:11px;}
.bf-col a{font-size:14px;color:var(--fg);text-decoration:none;width:fit-content;}
.bf-col a:hover{color:var(--sig);}
.bf-legal{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;margin-top:52px;padding-top:22px;border-top:1px solid var(--hair);font-family:'IBM Plex Mono',monospace;font-size:10.5px;letter-spacing:.08em;color:var(--mut);text-transform:uppercase;}

/* ============ v19: pinned builds restored on the rounded system ============ */
.faq{margin-top:36px;}
.ru{opacity:1;transform:none;transition:none;}

/* ============ v20: spacing & alignment pass ============ */
/* FAQ: cards keep their internal padding; more air under the // FAQ line and under each opened answer */
.home-flow .faq{margin-top:48px;gap:14px;}
.fq summary{padding:24px 28px;}
.fq .fq-a{padding:2px 28px 26px;}
.fq .fq-a p{margin-top:0;}
/* Stack research questions: legible and tucked close under their heading */
#stack .exp{font-size:13.5px;line-height:1.95;letter-spacing:0;}
#stack .exp li{margin-top:7px;}
#stack .exp li:first-child{margin-top:0;}
/* uniform breathing room beneath each section-head rule in the home flow */
.home-flow .sec-head{margin-bottom:38px;}

/* ============ v21: section decks (descriptor as readable subtitle, not a mono eyebrow) ============ */
.sec-deck{font-family:var(--fam-display);font-size:clamp(15px,1.7vw,19px);line-height:1.42;letter-spacing:-.015em;color:var(--mut);max-width:54ch;margin:-22px 0 34px;}
@media(max-width:640px){.sec-deck{margin-top:-8px;}}

/* ============ v22: audit pass — P1 (rhythm+borders), cut floating +, P2.E stack, P3 ============ */

/* P2.D — remove decorative section crosshair "+" marks */
.sec::after{display:none;}

/* P1-B — drop the harsh full-contrast rule above the FAQ; soften the section-head hairline */
.faq{border-top:none;}
.sec-head::before{background:linear-gradient(90deg,var(--hair) 0%,var(--hair) 60%,transparent 100%);}

/* P1-C — FAQ: kill the void above the cards, calm the card height */
.home-flow .faq{margin-top:6px;gap:10px;}
.fq summary{padding:20px 28px;}
.fq .fq-a{padding:2px 28px 24px;}

/* P1-A — one rhythm: uniform gap between a section's lead text and its first component */
.home-flow .record,.home-flow .chlist,.home-flow .steps{margin-top:30px!important;}

/* P2.E — Stack: research questions as a distinct, legible divided list */
#stack .exp{font-size:14px;line-height:1.55;letter-spacing:0;color:var(--fg);}
#stack .exp li{margin-top:0;padding:11px 0;border-bottom:1px solid var(--hair);}
#stack .exp li:last-child{border-bottom:none;}
#stack .exp li::before{content:"+  ";color:var(--sig);}

/* P3.F — inner-page hero ledes share one calm voice */
.hero.inner .hero-lede{font-family:var(--fam-display);font-size:16px;line-height:1.6;color:var(--mut);letter-spacing:0;}

/* P3.G — hairlines a touch more present for definition */
:root{--hair:rgba(20,23,28,.22);}
[data-theme="dark"]{--hair:rgba(233,235,238,.20);}

/* P4.A — full-contrast emphasis: home hero + base-layer research question.
   var(--fg) flips per theme (#e9ebee dark / #14171c light), so this reads as
   maximum contrast in both rather than a hard-coded white. */
.hero-c h1 .acc{color:var(--fg);font-weight:700;}
.hero-c .hero-lede{color:var(--fg);font-weight:700;}
.lead-em{color:var(--fg);font-weight:700;}

/* ============ manifesto as a single read ============
   The manifesto page drops the chapter numerals, the pinned scenes, and the
   index rail. One centred column, subheads, continuous scroll: it should feel
   like a long essay rather than a spec with sections. Title and body share the
   same measure, so the page reads as one column with even margins either side
   rather than text pinned to the left edge.
   Everything inside sits on the same measure: kicker, headline, lede, subheads,
   prose, the record block, the closing button, and the footer rule all start and
   end on the same two vertical lines. Anything that keeps its own max-width has
   to be released explicitly, or its right edge steps in and breaks the column. */
.reading{max-width:82ch;margin:0 auto;}
.reading .hero{text-align:left;padding-top:76px;}
.reading .hero h1{max-width:none;font-size:clamp(34px,4.4vw,52px);}
.reading .hero-lede{max-width:none;}
.reading ~ footer{max-width:82ch;margin-left:auto;margin-right:auto;}
.essay{margin-top:8px;}
/* The closing button is the one thing that sits centred: it ends the read rather
   than continuing it, so it reads as a full stop instead of another line of text. */
.essay .joinwrap{text-align:center;margin-top:48px;}
.mvt{margin-top:56px;scroll-margin-top:96px;}
.mvt:first-child{margin-top:64px;}
.mvt-h{font-family:var(--fam-display);font-size:clamp(23px,2.6vw,32px);line-height:1.15;letter-spacing:-.025em;font-weight:700;color:var(--fg);margin:0 0 18px;}
/* Newspaper setting: both edges of the column run flush. Hyphenation is what keeps
   justification honest, otherwise the browser pays for the flush right edge with
   rivers of white space between words. The limits stop it hyphenating short words
   or leaving one or two stranded letters at a line break. */
.essay .mch-body p{max-width:none;font-size:17px;line-height:1.82;margin:0 0 22px;text-align:justify;-webkit-hyphens:auto;hyphens:auto;-webkit-hyphenate-limit-before:4;-webkit-hyphenate-limit-after:4;hyphenate-limit-chars:8 4 4;}
/* A narrow column cannot absorb justification: gaps get wide enough to read as
   holes, so phones fall back to a ragged right edge. */
@media(max-width:640px){.mvt{margin-top:44px;}.reading .hero{padding-top:56px;}
.essay .mch-body p{font-size:16px;text-align:left;-webkit-hyphens:none;hyphens:none;}}

/* ============ the Form step links to the onboarding form ============
   The whole card is the hit area. It carries the signal border and an explicit
   link line at rest, so it reads as clickable without needing a hover. */
.step-link{display:block;text-decoration:none;color:inherit;cursor:pointer;border-color:var(--sig);transition:box-shadow .25s ease,transform .25s ease;}
.step-link:hover,.step-link:focus-visible{box-shadow:0 0 0 1.5px var(--sig),var(--shadow);transform:translateY(-2px);}
.step-cta{display:inline-flex;align-items:center;gap:8px;margin-top:16px;font-family:'IBM Plex Mono',monospace;font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--sig-text);text-decoration:underline;text-underline-offset:4px;}
.step-link:hover .lk-arrow{transform:translateX(3px);}
.lk-arrow{transition:transform .25s ease;}
@media(prefers-reduced-motion:reduce){.step-link,.lk-arrow{transition:none;}.step-link:hover{transform:none;}}

/* ============ the home hero owns the first screen ============
   The index rail belongs to the scrolling body, so it used to peek into the
   bottom left corner of the hero: one element hanging off to one side of an
   otherwise centred, symmetrical composition. Giving the hero a screen of its
   own puts the rail below the fold, where it appears the moment it becomes
   useful. 100svh rather than 100vh so mobile browser chrome cannot push the
   button off screen. */
.hero.hero-c{min-height:calc(100svh - 72px);box-sizing:border-box;display:flex;flex-direction:column;justify-content:center;padding:56px 0 72px;}
.hero-c h1{max-width:34ch;font-size:clamp(32px,4.2vw,56px);}
@media(max-width:860px){.hero.hero-c{min-height:0;padding:56px 0 24px;}}

/* ============ no orphaned words ============
   text-wrap:pretty tells the browser to look ahead at the last few lines of a
   block and rebalance them rather than leaving one word alone on the final line.
   Headings get balance instead, which evens out every line rather than just the
   end. Short words stranded mid-paragraph are handled in the generator, which
   binds them to the following word with a non-breaking space. */
p,li,figcaption,.hero-lede,.sec-deck,.v,.dr{text-wrap:pretty;}
h1,h2,h3,.mvt-h,.tp-name,.dh{text-wrap:balance;}

/* ============ inner-page heroes use a wider measure ============
   15ch of headline and 56ch of intro stopped around the halfway mark, so the
   right half of every inner page read as empty rather than as breathing room. */
.hero.inner h1{max-width:22ch;}
.hero.inner .hero-lede{max-width:72ch;}
/* the manifesto is a centred column and governs its own hero measure */
.reading .hero.inner h1,.reading .hero.inner .hero-lede{max-width:none;}

/* ============ the footer follows the column it sits under ============
   On indexed pages the body occupies the right-hand column of the rail grid, so a
   full-width footer rule crosses the page at a different left edge from the closing
   rule directly above it: two parallel lines that do not start in the same place.
   200px rail plus the 64px grid gap. Below 900px the rail stacks and the offset goes. */
.railgrid ~ footer{margin-left:264px;}
@media(max-width:900px){.railgrid ~ footer{margin-left:0;}}

/* ============ inner pages arrive whole ============
   The hero staggers its parts in: headline at .45s, intro at .6s. On the home page
   that is a designed entrance. On a tab you clicked deliberately it just means the
   intro drops in after the headline has settled, which reads as a glitch rather
   than as motion. Inner pages load complete. */
.hero.inner .kicker,.hero.inner .themes,.hero.inner h1,.hero.inner .hero-lede,.hero.inner .joinwrap,.hero.inner .joinnote{animation:none;opacity:1;transform:none;}

/* ============ blog placeholder cards ============
   Marked as placeholders so a reviewer cannot mistake one for a published post: a
   dashed edge rather than a solid one, no shadow, and the date slot says so. */
.bcard-ph{border-style:dashed;box-shadow:none;cursor:default;}
.bcard-ph .bc-img.ph{border-style:dashed;background:var(--bg);}
.bcard-ph h3,.bcard-ph p{color:var(--mut);}

/* ============ home hero lede ============
   The centred home lede was set at 700 further up. It now carries a long,
   deliberately open-ended paragraph, and at that length the bold reads as
   shouting rather than emphasis. Regular weight, same colour. */
.hero-c .hero-lede{font-weight:400;}

/* ============ mobile ============
   Read from the stylesheet rather than from a device, so these are conservative:
   nothing changes above 700px, and every rule below is additive.

   1. The top bar. RETIRED 2026-08-27. This block turned the nav into a sheet
      below 700px only; the v29 block at the end of this file does that at every
      width, and its rules sit later in the file at the same specificity, so they
      won here anyway. Left as a marker rather than a live rule set. What is kept
      below is the part that is still purely about small screens: the tighter bar
      padding and the 44px targets. */
@media(max-width:700px){
  .topbar{flex-wrap:nowrap;padding:12px 20px;}
  .tb-right{gap:4px;}
  .toggle{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;}
}

/* 2. Card padding. .dcol and the accordion kept desktop padding at every width. On a
      375px screen .doc takes 48px and .dcol took another 60px, leaving 267px of
      measure, the tightest column on the site. */
@media(max-width:560px){
  .dcol{padding:20px 20px 12px;}
  .chx summary{padding:18px 18px;gap:12px;}
  .chx-b{padding:2px 18px 22px;}
  .chx-b p{font-size:15.5px;line-height:1.75;}
  /* the section number and slash eat ~60px before the title starts */
  .sec-head .sl{display:none;}
  .sec-head .n{min-width:0;}
  .sec-head{gap:10px;}
}

/* 3. The section index rail (Home and Library). Above 900px it is a sticky vertical
      rail beside the content, which works. Below 900px the grid collapses to one
      column and the rail turns into a horizontally scrolling strip of [01] [02] …
      pinned above the page, boxed in top and bottom borders. It reads as a stray
      toolbar, duplicates a scroll the reader is about to do anyway, and is the first
      thing under the header. Hidden instead.
      .railgrid ~ footer{margin-left:0} is already set at this breakpoint, so there
      is no leftover indent once the column is gone. */
@media(max-width:900px){
  .railgrid .pagenav{display:none;}
}

/* ── Home hero: type scale and measure ───────────────────────────────────────
   The centred home hero was the only hero on the site taking the weak lede
   treatment. .hero-c re-overrode the house lede (Space Grotesk 19px at --fg,
   set earlier in this file) back down to IBM Plex Mono 13px at --mut, capped
   at 66ch. That put the page's most important paragraph at the smallest size
   on the site, in the lowest-contrast colour, in a monospace face, across the
   widest measure. Monospace is fine for the record plates and terminal blocks;
   it is the wrong tool for a running paragraph this long.

   Against a 56px h1, a 13px lede is a 4.3:1 step. Convention for this format
   is 2.5:1 to 4:1 (h1 48-72px, lede 18-22px). The values below land at 3.4:1.

   The h1 measure drops 34ch -> 20ch so the headline breaks deliberately into
   two balanced lines rather than overflowing one. text-wrap:balance is already
   set on .hero h1 and does the work once the measure lets it; the &nbsp; binds
   that were briefly on these headlines fought it and have been removed. */
.hero-c h1{
  max-width:20ch;
  font-size:clamp(36px,4.6vw,64px);
  line-height:1.08;
}
.hero-c .hero-lede{
  font-family:var(--fam-display);
  font-size:clamp(16.5px,2.2vw,19px);
  line-height:1.6;
  letter-spacing:0;
  font-weight:400;
  color:var(--fg);
  max-width:54ch;
  margin-top:28px;
}
@media(max-width:640px){
  .hero-c h1{max-width:16ch;font-size:clamp(34px,8.4vw,46px);}
  .hero-c .hero-lede{max-width:46ch;margin-top:22px;}
}

/* ============================================================================
   v23 · Research-press pass
   ----------------------------------------------------------------------------
   Four changes, agreed 2026-08-16, in response to "it looks like AI built it".

   1. TYPE. Space Grotesk plus mono plus electric blue is the default costume of
      every protocol landing page since about 2021, and the display face was the
      loudest single element. Running prose moves to Source Serif 4, headings to
      Archivo, and IBM Plex Mono keeps the data plates. IOVI publishes papers and
      models itself on the Linux Foundation and RISC-V, so a journal register is
      the honest one. The wordmark is SVG paths, so it is untouched.
   2. SURFACES. 18px radius plus two-layer drop shadows made every block read as
      a dashboard card. Radius drops to 4px and the shadows go; hairlines carry
      the definition, and hover moves the border rather than lifting the box.
   3. ACCENT. Ultramarine was doing brand, state, ornament and emphasis all at
      once, which is why the page looked busy and why eleven elements failed
      contrast in dark mode. It is now restricted to two roles: the primary
      action, and the current/active state. Ornament goes to --mut.
   4. COMPARISON. The two tinted + / - cards become a plain table. Markup change
      lives in gen_alt.py; the styling is at the end of this block.

   No copy was changed anywhere in this pass.
   ============================================================================ */

/* --- 1. type ------------------------------------------------------------- */
@font-face{font-family:'Source Serif 4';font-style:normal;font-weight:400;font-display:swap;src:url(fonts/source-serif-4-latin-400-normal.woff2) format('woff2');}
@font-face{font-family:'Source Serif 4';font-style:italic;font-weight:400;font-display:swap;src:url(fonts/source-serif-4-latin-400-italic.woff2) format('woff2');}
@font-face{font-family:'Source Serif 4';font-style:normal;font-weight:600;font-display:swap;src:url(fonts/source-serif-4-latin-600-normal.woff2) format('woff2');}
@font-face{font-family:'Source Serif 4';font-style:italic;font-weight:600;font-display:swap;src:url(fonts/source-serif-4-latin-600-italic.woff2) format('woff2');}
@font-face{font-family:'Archivo';font-style:normal;font-weight:500;font-display:swap;src:url(fonts/archivo-latin-500-normal.woff2) format('woff2');}
@font-face{font-family:'Archivo';font-style:normal;font-weight:600;font-display:swap;src:url(fonts/archivo-latin-600-normal.woff2) format('woff2');}
@font-face{font-family:'Archivo';font-style:normal;font-weight:700;font-display:swap;src:url(fonts/archivo-latin-700-normal.woff2) format('woff2');}

:root{
  --fam-display:'Archivo','Helvetica Neue',Helvetica,Arial,sans-serif;
  --fam-text:'Source Serif 4',Charter,Georgia,'Times New Roman',serif;
  --fam-mono:'IBM Plex Mono',ui-monospace,Menlo,monospace;
}

/* Serif at a given pixel size reads smaller than a grotesque, so the text scale
   moves up about a point and the leading opens slightly. Headings tighten,
   because Archivo carries a lower cap-to-x ratio than Space Grotesk did. */
body{font-family:var(--fam-text);font-size:17px;line-height:1.6;}

h1,h2,h3,h4,.sec-head b,.sec-head h2,.mvt-h,.dh,.tp-name,.sd-name,.bf-mark,
.card h3,.step h3,.chx b,.chl b,.layer b,.sb-layer b,.b-l,.as-name,
.closing h2,.hero h1{
  font-family:var(--fam-display);
  font-weight:700;
  letter-spacing:-.022em;
}
.tr-item{font-family:var(--fam-display);}

/* Running prose. Everything here was Space Grotesk and is now serif; the sizes
   are nudged to hold the same physical measure at the same character count. */
.mch-body p,.chx-b p,.fq .fq-a p,.prose p,.cols p,.card p,.step p,
.tp-desc,.tp-body p,.sd-desc,.sb-desc,.blog-empty,.lead{
  font-family:var(--fam-text);
}
.home-flow .mch-body p{font-size:18px;line-height:1.68;max-width:70ch;}
.chx-b p{font-size:17.5px;line-height:1.7;}
.fq .fq-a p{font-size:16.5px;line-height:1.7;}
.step p{font-size:16px;line-height:1.6;}
.card p{font-size:15.5px;line-height:1.6;}
.essay .mch-body p{font-size:18.5px;line-height:1.72;}

/* One paragraph class replaces ten copies of the same inline style, which had
   drifted to two different measures and made adjacent sections step in and out. */
.lead{font-size:17px;line-height:1.68;max-width:70ch;margin:0;}
.lead.mut{color:var(--mut);}
.lead-h{font-family:var(--fam-display);font-size:20px;font-weight:600;color:var(--fg);
        letter-spacing:-.018em;line-height:1.35;max-width:70ch;margin:36px 0 12px;}

/* The lede and the section decks stay serif: they are prose, not labels. */
.hero-lede,.hero-c .hero-lede,.hero.inner .hero-lede,.sec-deck{font-family:var(--fam-text);}
.hero-c .hero-lede{font-size:clamp(17.5px,2.2vw,20px);line-height:1.55;letter-spacing:0;}
.sec-deck{font-size:clamp(16px,1.7vw,19px);line-height:1.45;letter-spacing:-.006em;font-style:italic;}
.hero h1,.hero-c h1{letter-spacing:-.028em;}
.closing h2{letter-spacing:-.026em;}

/* Mono stays mono, but the accordion gloss was 10px uppercase with .14em tracking,
   which is the least readable setting on the site applied to some of its most
   useful writing. Sentence case at 12px; the source strings are already lowercase. */
.chx .ct,.chl .ct{font-size:12px;letter-spacing:.01em;text-transform:none;color:var(--mut);}

/* --- 2. surfaces --------------------------------------------------------- */
/* Kept as a valid shadow value rather than `none`, because .step-link:hover
   composes var(--shadow) into a comma list and `none` inside a list is invalid
   CSS, which would drop the whole declaration. */
:root,[data-theme="dark"]{--shadow:0 0 0 0 transparent;--shadow-h:0 0 0 0 transparent;}

.card,.pf,.fq,.step,.chl,.chx,.stack,.record,.bench,.dcol,
.stack-detail,.track-viewer,.specb,.layer,.sb-layer,.tr-item,
.blog-empty,.b-pending,.modal-card,.bcard .bc-img,.type-sample{border-radius:4px;}
.sk,.toggle,.yours{border-radius:3px;}
.joinbtn{border-radius:3px;}
.sw,.b-track{border-radius:2px;}

/* Hover moves the edge instead of lifting the box. */
a.card:hover,.card:hover,a.pf:hover,.chl:hover,.chx:hover,.step-link:hover{
  transform:none;box-shadow:none;border-color:var(--line);
}
.step-link:hover,.step-link:focus-visible{box-shadow:inset 0 0 0 1px var(--sig);transform:none;}
.dcol.di{box-shadow:none;}

/* --- 3. accent discipline ------------------------------------------------ */
/* Ultramarine now means "the action" and "you are here". Everything that was
   using it as ornament moves to --mut, which also clears the dark-mode contrast
   failures at the source rather than by lightening the blue. */
.sec-head .n,.chx .cn,.chl .cn,.step .sn,.card .tag,.pf .tag{color:var(--mut);}
#stack .exp li::before{color:var(--mut);}
.fq[open] summary::after{color:var(--fg);}
.bf-col a:hover{color:var(--fg);}

/* What stays blue is state, and it gets the lightened token in dark mode so it
   clears 4.5:1. The v14 rule aimed at .steps .stn, a class the generator never
   emits (it writes .step .sn), which is why these went unfixed for two weeks. */
.railgrid .pagenav a.on .rn,.tr-item.active .trn,.tr-item.match .trn,
.step-cta,.term .tp1{color:var(--sig-text);}
.tr-item.match::after{background:var(--sig-text);}

/* --- 4. the comparison table --------------------------------------------- */
.dtable{width:100%;border-collapse:collapse;margin-top:34px;table-layout:fixed;}
.dtable th{
  font-family:var(--fam-display);font-size:15px;font-weight:700;letter-spacing:-.01em;
  text-align:left;padding:0 28px 12px 0;border-bottom:1.5px solid var(--line);color:var(--fg);
}
.dtable th:last-child,.dtable td:last-child{padding-right:0;color:var(--mut);}
.dtable td{
  font-family:var(--fam-text);font-size:16.5px;line-height:1.5;vertical-align:top;
  padding:16px 28px 16px 0;border-bottom:1px solid var(--hair);
}
.dtable tr:last-child td{border-bottom:none;}
@media(max-width:640px){
  /* Two 16px columns will not fit a phone. Each row becomes a stacked pair, with
     the column headings repeated inline so the pairing survives the reflow. */
  .dtable,.dtable tbody,.dtable tr,.dtable td{display:block;width:100%;}
  .dtable thead{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);}
  .dtable tr{padding:14px 0;border-bottom:1px solid var(--hair);}
  .dtable tr:last-child{border-bottom:none;}
  .dtable td{padding:0;border:none;}
  .dtable td+td{margin-top:6px;}
  .dtable td::before{
    content:attr(data-l);display:block;font-family:var(--fam-mono);font-size:9.5px;
    letter-spacing:.16em;text-transform:uppercase;color:var(--faint,var(--mut));margin-bottom:3px;
  }
}

/* --- 5. layout corrections ----------------------------------------------- */
/* A two-card row stretched the shorter card to match its neighbour, leaving
   about 80px of dead space inside it. */
.cards,.cards.two{align-items:start;}
/* The skill chips were centred inside an otherwise left-aligned section. */
.skills{justify-content:flex-start;}
/* One card in the blog row should not stretch across a third of the page. */
.bloggrid.bg-1{grid-template-columns:minmax(0,380px);}
.bloggrid.bg-2{grid-template-columns:repeat(2,minmax(0,1fr));max-width:780px;}
/* The library page no longer sits in a rail grid, so its footer loses the indent. */

/* The skip control sat at 10px in .3-alpha grey on black, which is hard to find at
   the moment you most want it. Full contrast, 11px, and a real hit target. */
.iv-skip{font-size:11px;color:#e9ebee;border-color:rgba(233,235,238,.55);padding:11px 18px;}
.iv-skip:hover{background:rgba(233,235,238,.10);}
/* The veil is a dark moment in a light-default site; its type follows suit. */
.iv-type{font-family:var(--fam-mono);}
.iv-line{font-family:var(--fam-mono);}

/* Two tracks do not earn a 240px vertical rail: the column sat empty for most of
   the panel's height. The rail becomes a row above the viewer, and stays a rail
   only if the group list ever grows past four. */
.trackgrid{grid-template-columns:minmax(0,1fr);gap:16px;}
.track-rail{position:static;flex-direction:row;flex-wrap:wrap;gap:8px;}
.tr-item{flex:0 0 auto;}
/* The signal border on the onboarding card is the exact ultramarine, which all but
   disappears against the dark ground. State colour follows --sig-text in dark. */
.step-link{border-color:var(--sig-text);}
.step-link:hover,.step-link:focus-visible{box-shadow:inset 0 0 0 1px var(--sig-text);}

/* ============================================================================
   v24 · Corrections from review, 2026-08-16
   ============================================================================ */

/* --- manifesto measure: keep the original wide column ---------------------
   NOTE: never write a literal comment terminator inside a comment here. Doing
   exactly that is what silently killed .reading for two weeks, because CSS
   error recovery swallows the following rule along with the stray text.

   The v23 pass closed that orphaned terminator, which made .reading apply for
   the first time and narrowed the essay to 82ch. Cara's call: the wide measure
   is the intended one and 82ch reads too narrow. The rule stays valid but
   releases the width,
   so the essay sits at the full document measure as it always did. The real
   defect was never the width: it was that .reading ~ footer DID parse, so the
   footer sat on a different left edge from the text above it. Both now run to
   the same two vertical lines. */
.reading{max-width:none;margin:0;}
.reading ~ footer{max-width:none;margin-left:0;margin-right:0;}

/* --- the // eyebrow is gone from the markup; retire its style ------------- */
.sec-head .sl{display:none;}

/* --- vertical rhythm ------------------------------------------------------
   The old spacing was tuned around Space Grotesk at 15-17px and a mono deck.
   Serif text sits on a different baseline and three sections lost their deck
   entirely, so the section head had a negative-margin hack compensating for a
   gap that no longer exists. One rhythm, stated once, in multiples of 2px:

     section rule    -> 20px -> heading -> 14px -> deck -> 30px -> body
     last body block -> 84px -> next section rule
*/
.home-flow .sec{margin-top:84px;}
.home-flow .sec:first-child{margin-top:72px;}
.sec-head{padding-top:20px;margin-bottom:0;gap:14px;}
.sec-deck{margin:14px 0 0;}
/* One uniform gap between a section's head (or deck) and whatever follows,
   whichever of the two comes last. Replaces the v22 !important patch and the
   inline margin-top values that were stripped out of the generator. */
.home-flow .sec-head + *,
.home-flow .sec-deck + *,
.sec-head + *,
.sec-deck + *{margin-top:30px;}
/* .record/.chlist/.steps carried margin-top:30px!important from v22, which
   would otherwise beat the rule above in the cases where 30px is not wanted. */
.home-flow .record,.home-flow .chlist,.home-flow .steps{margin-top:30px!important;}
.home-flow .faq{margin-top:30px;gap:10px;}
.home-flow .mch-body p:last-child{margin-bottom:0;}
/* Body blocks that follow prose rather than a heading. */
.mch-body + .record,.mch-body + .chlist,.mch-body + .diff,.mch-body + .dtable,
.lead + .record,.lead + .dtable,.lead + .exp{margin-top:30px;}
.lead-h{margin:34px 0 10px;}
#stack .exp{margin-top:0;}
.dtable{margin-top:30px;}
.steps{margin-top:30px;}
.callout{margin-top:30px;}
.closing{padding:64px 0 36px;}
@media(max-width:640px){
  .home-flow .sec{margin-top:60px;}
  .sec-head{padding-top:16px;}
}

/* --- scroll motion retired ------------------------------------------------
   Companion to the guards in v8-extra.js and iovi.js. The scene engine wrote
   inline opacity and transform onto every unit and onto the hero, so these use
   !important: an author !important declaration beats a non-important inline
   style, which means a stale cached script cannot leave content invisible.
   Sections are now as tall as their content, and everything renders at once. */
.scene .scn-wrap{height:auto!important;}
.scene .scn-stage{position:static!important;top:auto!important;min-height:0;padding-bottom:0;}
.scn-u,.epi,.band{opacity:1!important;transform:none!important;}
.hero,.hero:not(.inner){opacity:1!important;transform:none!important;visibility:visible!important;}
.reveal,.rv,.ru{opacity:1!important;transform:none!important;transition:none!important;}

/* --- rhythm, corrected specificity ---------------------------------------
   The v24 block above stated the rhythm but lost two fights: v20's
   `.home-flow .sec-head{margin-bottom:38px}` outranked a bare `.sec-head`,
   and `.sec-head + *` matched the deck itself, handing it the 30px body gap
   instead of its own 14px. Both are pinned here, and the deck is excluded
   from the body-gap rule by name.

     rule -> 20px -> heading -> 14px -> deck -> 30px -> first body block
     rule -> 20px -> heading -> 30px -> first body block   (no deck)
*/
.sec-head,.home-flow .sec-head{margin-bottom:0;}
.sec-head + .sec-deck,.home-flow .sec-head + .sec-deck{margin-top:14px;}
.sec-head + :not(.sec-deck),
.home-flow .sec-head + :not(.sec-deck),
.sec-deck + *,
.home-flow .sec-deck + *{margin-top:30px;}
/* A section head whose deck was deleted must not keep the deck's old offset. */
.sec-deck{margin-bottom:0;}

/* ============================================================================
   v25 · Review round two, 2026-08-16
   ============================================================================ */

/* --- alignment ------------------------------------------------------------
   The section numeral sat in the head with min-width:36px and a 14px gap, so
   every h2 started ~50px right of the deck and body beneath it: three different
   left edges inside one section. Numeral and anchor are out of the markup; this
   clears their styles and puts the head on the same edge as everything else. */
.sec-head{display:block;padding-top:16px;margin:0;}
.sec-head .n,.sec-head .sl,.anch{display:none;}
.sec-head h2,.sec-head b{margin:0;}

/* --- the corner brackets --------------------------------------------------
   Four L-shaped marks pinned to the viewport corners. It is a real device with
   a real history (crop and registration marks on press sheets) but it has been
   the house style of technical and crypto landing pages for years, so it now
   reads as costume rather than as craft. Removed; the class stays so it can be
   restored by deleting one line. */
.frame{display:none;}

/* --- spacing: one tighter scale ------------------------------------------
   "assume all spacing is tighter, it looks poorly made". Every gap below is a
   multiple of 4px and steps down from the previous pass.

     rule -> 16 -> heading -> 24 -> body -> 60 -> next rule
*/
.home-flow .sec,.sec{margin-top:60px;}
.home-flow .sec:first-child{margin-top:52px;}
.sec-head + .sec-deck,.home-flow .sec-head + .sec-deck{margin-top:10px;}
.sec-head + :not(.sec-deck),
.home-flow .sec-head + :not(.sec-deck),
.sec-deck + *,
.home-flow .sec-deck + *{margin-top:24px;}
.home-flow .record,.home-flow .chlist,.home-flow .steps{margin-top:24px!important;}
.home-flow .faq{margin-top:24px;gap:8px;}
.chlist{gap:8px;}
.dtable,.steps,.callout,.diff{margin-top:24px;}
.mch-body + .record,.mch-body + .chlist,.mch-body + .dtable,
.lead + .record,.lead + .dtable,.lead + .exp{margin-top:24px;}
.lead-h{margin:28px 0 8px;}
.cards,.proof,.skills,.trackgrid{margin-top:24px;}
.mch-body p{margin-bottom:14px;}

/* the closing call to action and the footer beneath it */
.closing{padding:48px 0 28px;}
.closing .joinwrap{margin-top:32px;}
footer,footer.bigfoot{margin-top:56px;padding-top:20px;}

@media(max-width:640px){
  .home-flow .sec,.sec{margin-top:44px;}
  .sec-head{padding-top:14px;}
}

/* --- hero: one group, not four stranded objects ---------------------------
   The mark, headline, lede and button were spread down a full viewport with
   ~170px of air between the mark and the headline and a long six-line lede,
   so the block read as scattered rather than composed. The measure narrows so
   the lede sets in four lines, the internal gaps tighten, and the hero no
   longer reserves a whole screen it cannot fill. */
.hero.hero-c{min-height:0;padding:64px 0 56px;display:block;}
.hero-c .hero-art{margin:0 auto 20px;}
.hero-c .hero-art svg{height:56px;}
.hero-c h1{margin:0 auto;max-width:18ch;font-size:clamp(38px,5.2vw,68px);line-height:1.04;}
.hero-c .hero-lede{margin:20px auto 0;max-width:46ch;font-size:clamp(16px,1.9vw,18px);line-height:1.55;}
.hero-c .joinwrap{margin-top:28px;}
@media(max-width:860px){.hero.hero-c{padding:44px 0 40px;}}
@media(max-width:640px){.hero-c h1{max-width:15ch;}.hero-c .hero-lede{max-width:38ch;}}

/* ============================================================================
   v29 · Inter carries the site, IBM Plex Mono carries the data
   ----------------------------------------------------------------------------
   This is the two-line change the v26 pass below was holding open. v26 withdrew
   the research-press serif pairing and set the target: one sans carrying
   everything with IBM Plex Mono for data, just not a face that announces itself
   as the default choice. Space Grotesk stayed live in the meantime so the
   structural work could be judged with the type held constant.

   Inter is the winner, chosen 2026-08-27 against two references Cara supplied:
   ludwig.ai runs Inter with Geist Mono and JetBrains Mono, and beeai.dev runs
   IBM Plex Sans with IBM Plex Mono. Both are one sans plus one mono and neither
   uses a serif, which is the same structure v26 asked for. Space Grotesk with
   IBM Plex Mono is the most recognisable crypto and AI startup template pairing
   there is, and that was the thing reading as generic.

   Space Grotesk, Archivo and Source Serif 4 @font-face blocks stay in the file
   and their woff2 files stay on disk. gen_v3.py and gen_site3.py build other
   versions of this site from the same stylesheet, and gen_og.py rasterises the
   OG card from archivo-latin-700-normal. Deleting the faces would break those.
   Nothing on the shipped pages references them any more.
   ============================================================================ */
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(fonts/inter-latin-400-normal.woff2) format('woff2');}
@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(fonts/inter-latin-500-normal.woff2) format('woff2');}
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(fonts/inter-latin-600-normal.woff2) format('woff2');}
@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(fonts/inter-latin-700-normal.woff2) format('woff2');}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:400;font-display:swap;src:url(fonts/space-grotesk-latin-400-normal.woff2) format('woff2');}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:500;font-display:swap;src:url(fonts/space-grotesk-latin-500-normal.woff2) format('woff2');}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:600;font-display:swap;src:url(fonts/space-grotesk-latin-600-normal.woff2) format('woff2');}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:700;font-display:swap;src:url(fonts/space-grotesk-latin-700-normal.woff2) format('woff2');}

:root{
  --fam-display:'Inter','Helvetica Neue',Helvetica,Arial,sans-serif;
  --fam-text:'Inter','Helvetica Neue',Helvetica,Arial,sans-serif;
}

/* A grotesque sets larger on the body than a serif at the same pixel size, so
   the v23 scale (tuned up for Source Serif) comes back down to the values the
   live site was already using. */
body{font-family:var(--fam-text);font-size:16px;line-height:1.55;}
/* Tabular figures wherever numbers sit in a column or want to hold position. */
.record .v,.rn,.sn,.cn,.stamp,.fd-cap{font-variant-numeric:tabular-nums;}
.home-flow .mch-body p{font-size:17px;line-height:1.7;max-width:74ch;}
.chx-b p{font-size:16px;line-height:1.75;}
.fq .fq-a p{font-size:14.5px;line-height:1.75;}
.step p{font-size:14.5px;line-height:1.7;}
.card p{font-size:13.5px;line-height:1.65;}
.essay .mch-body p{font-size:17px;line-height:1.82;}
.lead{font-size:15px;line-height:1.7;max-width:74ch;}
.lead-h{font-size:19px;font-weight:600;letter-spacing:-.015em;line-height:1.4;}
.dtable td{font-family:var(--fam-text);font-size:14.5px;line-height:1.6;}
.dtable th{font-size:15px;}
.hero-c .hero-lede{font-family:var(--fam-text);letter-spacing:0;}
/* The italic deck was an editorial-serif gesture. Back to upright, muted. */
.sec-deck{font-style:normal;font-size:clamp(15px,1.6vw,17px);line-height:1.45;}
h1,h2,h3,.sec-head h2,.closing h2,.hero h1{letter-spacing:-.03em;}

/* Hero lede measure. Narrowing it to 46ch was the wrong direction: the string is
   ~310 characters, so a tighter measure pushed it from five lines to six and made
   the lede block taller than the two-line headline above it. Widening lets it set
   in four, which balances against the headline instead of competing with it. */
.hero-c .hero-lede{max-width:68ch;}
@media(max-width:640px){.hero-c .hero-lede{max-width:42ch;}}

/* --- v27 ------------------------------------------------------------------
   Two cards of very different length sat in one row. v23 set align-items:start
   to kill ~80px of dead space inside the shorter one, but that was my note from
   the audit, not a complaint, and the cure was worse: the two boxes ended at
   different heights and the row read as broken rather than as breathing. Boxes
   in a row match; the air inside the shorter one is the cost of using boxes. */
.cards,.cards.two,.steps{align-items:stretch;}

/* Dark is the default theme now, so the light palette is the alternate. Nothing
   about the tokens changes: both themes were already defined token-level, and
   the toggle still wins in either direction. */

/* --- v28: index rail tap targets -----------------------------------------
   Found by the post-deploy audit. The rail links were 15.5px tall, under the
   24px minimum (WCAG 2.5.8). Padding goes on, the flex gap comes off by the
   same amount, so each row still sits 26.5px from the next and the rail looks
   identical: only the hit area changes. */
.railgrid .pagenav{gap:1px;}
.railgrid .pagenav a{padding:5px 0;}

/* ==================== Fig 01, event-state dissociation ====================
   Replaces the two-row Base / Semantic layer plate in the Stack section.
   Unboxed and full width since 2026-08-27. It used to sit in a --paper card beside
   a 300px readout panel, which left the drawing 488px wide inside an 888px column:
   the 9.5px labels in a 800-unit viewBox came out near 5.8px on screen, too small to
   read. The panel moved under the figure (where the mobile layout already put it) and
   the card chrome came off, so the drawing takes the full 888px and its labels land
   around 10.5px. The card was not carrying contrast: ink on --paper is 15.9:1 in light
   and 14.3:1 in dark, against 14.2:1 and 15.5:1 on the plain --bg, so removing it costs
   nothing in light and gains a little in dark. Both pass AA either way.
   All colour comes from the theme tokens so the figure inverts with the page;
   the BASE LAYER label uses --sig-text because raw ultramarine fails AA on the
   dark canvas. Class and pattern ids are fd-prefixed: .flow and .sel are taken. */
/* Readout back beside the drawing, 2026-08-27. Full width put it under the figure
   and the eye had to travel down to read what it was hovering. The drawing is only
   affordable at this width because the viewBox was cropped to the artwork first:
   it was carrying 15% empty margin horizontally and 28% vertically, so cropping
   buys back most of what the 260px column costs. 260px holds the longest readout
   in about twelve lines, which stays inside the figure's own height, so the row
   never grows taller than the drawing. */
.fdis{display:grid;grid-template-columns:1fr 260px;gap:32px;align-items:center;margin-top:34px;}
.fdis svg{width:100%;height:auto;display:block;}
.fd-hot{cursor:pointer;outline:none;}
.fdis .fd-hot text{font-family:var(--fam-display),'Space Grotesk',sans-serif;}
.fdis .fd-flow text{font-family:var(--fam-mono),'IBM Plex Mono',monospace;}
.fd-hot polygon,.fd-hot text,.fd-hot path{transition:opacity .28s ease;}
.fd-box.on .fd-hot{opacity:.36;}
.fd-box.on .fd-hot.fd-sel{opacity:1;}
.fd-hot:focus-visible polygon{stroke-width:2.6;}
.fd-flow line,.fd-flow path,.fd-flow text{transition:opacity .28s ease;}
.fd-box.on .fd-flow{opacity:.3;}
.fd-cap{font-family:var(--fam-mono),'IBM Plex Mono',monospace;font-size:10px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--mut);margin-top:16px;}
/* 160px is the measured height of the tallest readout (the boundary entry) at the
   74ch measure, so hovering a layer never nudges what follows the figure. */
.fd-panel{min-height:200px;border-left:1.5px solid var(--hair);padding-left:24px;}
.fd-panel .fd-b,.fd-panel .fd-idle{max-width:none;}
.fd-k{font-family:var(--fam-mono),'IBM Plex Mono',monospace;font-size:10px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--mut);}
.fd-t{font-family:var(--fam-display);font-size:23px;font-weight:700;
  letter-spacing:-.02em;margin:12px 0 10px;line-height:1.15;color:var(--fg);}
.fd-b{font-size:14px;line-height:1.65;color:var(--fg);opacity:.88;}
.fd-idle{font-size:14px;line-height:1.65;color:var(--mut);}
@media(max-width:820px){
  .fdis{grid-template-columns:1fr;gap:20px;}
  .fd-panel{min-height:0;border-left:none;border-top:1.5px solid var(--hair);padding:18px 0 0;}
}
@media(prefers-reduced-motion:reduce){
  .fd-hot polygon,.fd-hot text,.fd-hot path,
  .fd-flow line,.fd-flow path,.fd-flow text{transition:none;}
}

/* ── Index rail, nested (Home) ────────────────────────────────────────────────
   Base layer and Stack belong to the Thesis, and Process belongs to Status, so
   the rail sets them as children rather than as four more peers in a flat run of
   seven. The numeral stays in the margin and the child label starts on the same
   left edge as its parent's label, which makes it a hanging indent: the numerals
   read as a column of their own and everything under one numeral is visibly one
   part of the page. The indent is a hidden [00] in the child's own markup rather
   than a padding value: the link is a flex row of numeral + gap + label, so an
   identical hidden box is the only indent that cannot drift out of alignment when
   the mono advance, the letter-spacing or the flex gap changes.
   Rail-only: below 900px .railgrid .pagenav is hidden outright, and .pagenav
   without .railgrid (the "On this page" nav) never gets sub entries. */
.railgrid .pagenav a.sub .rn{visibility:hidden;}

/* ── v29 · Nav collapses to a hamburger at every width ────────────────────────
   The four links used to sit inline on desktop and behind a button only below
   700px. They are behind the button at all widths now: hover opens it with a
   pointer, tap opens it on touch.

   The button and the panel share .tb-menuwrap so :hover stays true while the
   pointer travels from the icon down into the panel. :hover follows the DOM, not
   the layout, so an absolutely positioned panel still counts as inside its
   wrapper. The wrapper is stretched over the topbar's vertical padding with a
   negative margin and matching padding, which changes nothing about the layout
   but puts its bottom edge flush with the topbar's border. Without that the
   panel would open 18px below the wrapper and the pointer would cross dead space
   on the way down, closing it.

   The hover rule is gated on (hover:hover) and (pointer:fine). A touch browser
   that reports a lingering :hover would otherwise open the panel on the tap that
   is also toggling .nav-open, and the two would fight.

   Click still pins the panel open through .nav-open, so hover previews and click
   holds. Both paths are keyboard-reachable: :focus-within opens it on tab. */
.tb-menuwrap{position:relative;display:flex;align-items:center;align-self:stretch;
  margin-block:-18px;padding-block:18px;}
.tb-menu{display:inline-flex;align-items:center;justify-content:center;
  width:40px;height:40px;background:none;border:0;padding:0;color:var(--fg);cursor:pointer;}
.tb-menu .ic-x{display:none;}
.topbar.nav-open .tb-menu .ic-x{display:block;}
.topbar.nav-open .tb-menu .ic-bars{display:none;}

.tb-nav{position:absolute;top:100%;right:0;left:auto;z-index:30;
  display:none;flex-direction:column;gap:0;width:min(78vw,300px);
  background:var(--bg);border:1.5px solid var(--line);border-top:0;padding:4px 18px;}
.topbar.nav-open .tb-nav{display:flex;}
@media(hover:hover) and (pointer:fine){
  .tb-menuwrap:hover .tb-nav,
  .tb-menuwrap:focus-within .tb-nav{display:flex;}
}
/* 44px minimum touch target (WCAG 2.5.8): 14px of padding on a 16px line. */
.tb-nav a{padding:14px 2px;font-size:12px;border-bottom:1px solid var(--hair);border-left:0;}
.tb-nav a:last-child{border-bottom:0;}
/* Stacked, an aria-current border reads as a divider rather than a marker, so the
   active page is carried by weight and colour alone. */
.tb-nav a[aria-current="page"]{border-bottom-color:var(--hair);}
.tb-nav a:last-child[aria-current="page"]{border-bottom-color:transparent;}
@media(max-width:860px){.topbar{flex-wrap:nowrap;padding:14px 20px;}
  .tb-menuwrap{margin-block:-14px;padding-block:14px;}}
/* The bar tightens again at 700px, so the wrapper's stretch has to follow it or
   the panel reopens a gap under the icon. 44px targets on touch. */
@media(max-width:700px){.tb-menuwrap{margin-block:-12px;padding-block:12px;}
  .tb-menu{width:44px;height:44px;}}

/* ── v29 · Wordmark ──────────────────────────────────────────────────────────
   22px left the mark smaller than the theme toggle beside it. 26px reads as the
   primary element in the bar without crowding the 1.5px rule under it. */
.tb-mark svg{height:26px;}
@media(max-width:640px){.tb-mark svg{height:22px;}}

/* ── v29 · Closing headline ──────────────────────────────────────────────────
   26ch broke the line into three, which set the sentence as a stack rather than
   a statement. The measure opens to 40ch and the size comes down, so it lands in
   two. The non-breaking spaces inside "neutral value" and "coordination
   substrate" stay: they are what stops either pair splitting across the break
   and stranding a word, per the house rule on orphans. */
.closing h2{font-size:clamp(26px,3.1vw,40px);max-width:40ch;}
@media(max-width:640px){.closing h2{max-width:24ch;}}

/* ── v29 · Hero is static ─────────────────────────────────────────────────────
   iovi.css:56 starts the kicker, headline, lede and CTA at opacity:0 and fades
   each one up on a stagger, and the headline additionally rises word by word.
   Cara wants the hero to be there when the page is. Neutralised here rather than
   in iovi.css because that file is shared with gen_v3.py, gen_site3.py and
   gen_asm.py, which still build their own versions of this site.

   This is the same declaration set the prefers-reduced-motion block in iovi.css
   already applies, promoted to apply always. */
.hero .kicker,.hero .themes,.hero h1,.hero .hero-lede,
.hero .joinwrap,.hero .joinnote{animation:none!important;opacity:1;transform:none;}
.hero h1 .hw{opacity:1;transform:none;animation:none!important;}

/* ── v29 · Mono is for accents only ───────────────────────────────────────────
   Audited every text-bearing element on Home for its computed family. Two were
   setting full sentences in IBM Plex Mono rather than labelling anything:

     .record .v   the record plate's values, e.g. "A base layer that orders
                  economic events and keeps them retrievable, without reading
                  them". Its label, .record .k, is a real accent and stays mono.
     .exp li      the Stack section's open questions, which are whole sentences
                  ending in question marks.

   Both are running text, so both move to Inter. Everything still on mono is a
   label, a numeral or a kicker: the index rail and its [01] figures, the nav,
   record keys, step and accordion numerals, the figure's annotations and its
   readout kicker, and the footer stamp. Set in iovi.css, overridden here because
   that file is shared with three other generators. */
.record .v{font-family:var(--fam-text);font-size:14px;line-height:1.6;letter-spacing:0;}
.exp{font-family:var(--fam-text);letter-spacing:0;}
#stack .exp,#stack .exp li{font-family:var(--fam-text);letter-spacing:0;}

/* ── v31 · Plain Inter, set the way luigi-project.io sets it ──────────────────
   "I just want normal Inter." Previous passes kept inherited display settings on
   top of it: 700 weight, negative tracking, and 1.04-1.12 leading, all of which
   were tuned for Space Grotesk and none of which Inter asks for. Stacked up they
   stop reading as Inter at all.

   Luigi, the reference, sets headings at font-weight:normal, line-height:1.4 and
   no letter-spacing whatsoever. That is what this is. Every negative tracking
   value on a heading is gone rather than reduced, weight drops to 400, and the
   leading opens. Display sizes keep a little less leading than 1.4 only because
   they are three to four times Luigi's heading sizes, where 1.4 would open the
   lines past the point of reading as one headline.

   Reverting to bold is one line: change the font-weight below. */
h1,h2,h3,h4,.hero h1,.hero-c h1,.sec-head h2,.sec-head b,.closing h2,.mvt-h,.dh{
  font-weight:400;letter-spacing:normal;}
.hero h1,.hero-c h1{line-height:1.16;}
.sec-head h2,.sec-head b,.mvt-h,.dh{line-height:1.2;}
.closing h2{line-height:1.28;}
h3,.step h3,.card h3,.fd-t,.sd-name,.tp-name{font-weight:600;letter-spacing:normal;line-height:1.35;}
p,li,.lead,.lead-h,.lead-em,.sec-deck,.hero-lede,.mch-body p,
.fd-b,.fd-idle,.record .v,.exp,.exp li{letter-spacing:normal;}

/* ── v30 · The closing CTA is not a fenced enclosure ──────────────────────────
   .closing carried border-top:1.5px solid var(--line) and <footer> carries the
   same, so the CTA sat between two full-width rules at full ink weight: --line
   is the foreground colour, not a hairline. Two hard rules that close ranks
   around one sentence and a button read as a boxed-off panel. The band's own
   rule comes off and the footer's drops to --hair, which still divides the
   footer from the page without fencing the CTA in. */
.closing{border-top:0;padding-top:40px;}
footer{border-top:1.5px solid var(--hair);}

/* ── v30 · Topbar: two links inline, the rest in the menu ─────────────────────
   Contribute / Participate and Research sit inline because they are what the
   site is asking of a reader. Home, Blog and the socials live in the menu. The
   inline pair inherits .tb-nav's type but not its panel layout, so it is styled
   from scratch rather than by unpicking the panel rules. Hidden below 700px,
   where the bar has no room for them and the menu already holds everything. */
.tb-inline{display:flex;align-items:center;gap:22px;
  font-family:var(--fam-mono),'IBM Plex Mono',monospace;font-size:11px;
  letter-spacing:.14em;text-transform:uppercase;}
.tb-inline a{color:var(--mut);text-decoration:none;padding:2px 0;
  border-bottom:1.5px solid transparent;transition:color .25s ease;}
.tb-inline a:hover{color:var(--fg);}
.tb-inline a[aria-current="page"]{color:var(--fg);font-weight:600;border-bottom-color:var(--line);}
@media(max-width:700px){.tb-inline{display:none;}}

/* Socials close the menu panel, under the same hairline the nav links use so the
   row reads as part of the list rather than as a separate tray. The icons are
   the footer's, from the one SOCIALS constant, so the two can never drift. */
.tb-social{display:flex;align-items:center;gap:16px;padding:14px 2px 4px;}
.tb-social a{color:var(--mut);display:inline-flex;padding:0;border:0;
  transition:color .25s ease;}
.tb-social a:hover{color:var(--fg);}

/* ── v31 · Bar is chrome, content is a centred column ────────────────────────
   Two things Cara asked for at once, and they pull in opposite directions until
   the roles are separated. The prose was running hard against the left with all
   the slack piling up on the right, because the column was the full 1152px while
   the paragraphs capped at 70ch, about 794px. And the wordmark and the menu were
   sitting too far in from the window edges.

   So the bar stops sharing the content's grid. It spans the window on a small
   fixed inset, which is what puts the wordmark and menu near the edges, and the
   content becomes a column sized to the measure it actually sets and centred, so
   the slack falls evenly on both sides instead of all to the right. The earlier
   pass had done the opposite, pinning the bar to the column, which was right
   when the column was full width and is wrong now.

   .doc is 968px so its content box is 880px, which is the paragraph measure plus
   a little. Everything in the column shares that width: headings, rules, cards,
   the figure and the FAQ, so nothing is left hanging into empty space. */
:root{--gutter:44px;}
@media(max-width:860px){:root{--gutter:24px;}}
.doc{max-width:968px;padding-left:var(--gutter);padding-right:var(--gutter);}
.topbar{padding-left:28px;padding-right:28px;}
@media(max-width:860px){.topbar{padding-left:16px;padding-right:16px;}}

/* The prose caps come off inside the column: the column is the measure now, so a
   second, narrower cap would reintroduce the same right-hand gap one level in. */
.home-flow{max-width:none;margin:0;}
.home-flow .mch-body p,.lead,.fd-b,.fd-idle,.record .v{max-width:none;}

/* ── v31 · Theme toggle ───────────────────────────────────────────────────────
   It was a pill-bordered box, the only outlined control in the bar, sitting to
   the left of the menu. Bare icon now, same 40px hit area as the menu button so
   both still clear the 24px minimum, and last in the row. */
.toggle{border:0;background:transparent;border-radius:0;padding:0;
  width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;
  color:var(--mut);}
.toggle:hover{color:var(--fg);border-color:transparent;}
@media(max-width:700px){.toggle{width:44px;height:44px;}}
