html,body{height:100%}
body{overflow:hidden}
.ch{position:fixed;inset:0;display:grid;grid-template-columns:minmax(calc(380*var(--u)),40%) 1fr;padding-top:calc(112*var(--u));background:#000}
/* big, tall windows (desktop): the text column takes 30% and the picture gets the rest; every other window keeps 40%. From 1800 px wide, because below that the chapter strip (00 01 02 ... with the names under the numbers) gets too narrow for the name CAD model */
@media(min-width:1800px) and (min-height:800px){.ch{grid-template-columns:minmax(calc(380*var(--u)),30%) 1fr}
}
.panel{display:flex;flex-direction:column;padding:calc(8*var(--u)) var(--pad) 0;overflow:hidden;border-right:1px solid var(--line)}
.pbody{flex:1;min-height:0;overflow:auto;padding-bottom:calc(24*var(--u))}
.pfoot{flex:none;padding:calc(16*var(--u)) 0 calc(26*var(--u));border-top:0;background:#000}
.pfoot .dots{margin:0;height:calc(3*var(--u));overflow:hidden}
.pfoot .links{flex-wrap:nowrap;white-space:nowrap;gap:calc(28*var(--u));height:calc(22*var(--u));overflow:hidden}
.pfoot .chnav{margin-top:calc(22*var(--u))}
.ctl button:disabled{opacity:.25;pointer-events:none}
.pbody{-webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - calc(30*var(--u))),transparent);mask-image:linear-gradient(to bottom,#000 calc(100% - calc(30*var(--u))),transparent)}
.back{font-size:calc(11*var(--u));letter-spacing:.24em;text-transform:uppercase;color:var(--grey);margin-bottom:calc(18*var(--u))}
.back:hover{color:var(--red)}
.chnum{font-weight:900;font-size:clamp(calc(40*var(--u)),3.6vw,calc(64*var(--u)));line-height:.8;color:var(--red)}
.rule{height:2px;background:var(--red);transform-origin:left;transform:scaleX(0);margin:calc(22*var(--u)) 0 calc(18*var(--u))}
.go .rule{animation:draw 1.1s .15s cubic-bezier(.7,0,.2,1) forwards}
@keyframes draw{to{transform:scaleX(1)}}
.reveal{display:block;overflow:hidden}
.reveal>span{display:block;transform:translateY(105%)}
.go .reveal>span{animation:up .9s cubic-bezier(.2,.8,.2,1) forwards}
.go h2 .reveal>span{animation-delay:.3s}
@keyframes up{to{transform:none}}
.ch .label{font-size:calc(11*var(--u));letter-spacing:.26em}
.ch h2{font-size:clamp(calc(22*var(--u)),2vw,calc(34*var(--u)));line-height:1.05;letter-spacing:.01em;margin-top:calc(12*var(--u))}
.lede{font-size:calc(13.5*var(--u));line-height:1.75;letter-spacing:.01em;max-width:52ch;margin-top:calc(16*var(--u));color:#d6d6d6;opacity:0}
.lede p+p{margin-top:1.75em;text-align:left!important}
.go .lede{animation:fade .8s .6s forwards}
@keyframes fade{to{opacity:1}}
.cap{padding-top:calc(22*var(--u));border-top:1px solid var(--line);margin-top:calc(26*var(--u))}
.idx{font-weight:500;font-size:calc(11*var(--u));letter-spacing:.26em;color:var(--grey)}
.idx b{color:var(--paper);font-weight:500}
.cap h4{font-weight:700;text-transform:uppercase;font-size:calc(14*var(--u));letter-spacing:.08em;line-height:1.25;margin:calc(12*var(--u)) 0 calc(8*var(--u))}
.cap h4:empty{display:none}
.cap .line{font-size:calc(13*var(--u));line-height:1.75;letter-spacing:.01em;color:#b8b8b8;max-width:54ch}
.cap .line:empty{display:none}
.counter{font-weight:900;font-size:clamp(calc(30*var(--u)),2.6vw,calc(44*var(--u)));color:var(--red);line-height:1;margin:calc(10*var(--u)) 0 2px;display:none}
.counter small{font-size:.32em;font-weight:500;color:var(--paper);margin-left:calc(8*var(--u));letter-spacing:.12em}
.dots{display:flex;gap:calc(8*var(--u));margin-top:calc(14*var(--u))}
.dots button{width:calc(22*var(--u));height:calc(3*var(--u));padding:0;background:#333;border:0}
.dots button:hover{background:#777}
.dots button.on{background:var(--red)}
.ctl{display:flex;align-items:center;gap:calc(10*var(--u));margin-top:calc(18*var(--u))}
.ctl button{width:calc(46*var(--u));height:calc(46*var(--u));padding:0;background:none;border:1px solid #333;color:var(--paper);font-size:calc(18*var(--u));letter-spacing:0}
.ctl button:hover{border-color:var(--red);color:var(--red);background:none}
.bar{flex:1;height:2px;background:#222;position:relative;margin-left:calc(8*var(--u))}
.bar i{position:absolute;left:0;top:0;bottom:0;background:var(--red);transition:width .7s cubic-bezier(.7,0,.2,1)}
.links{display:flex;flex-wrap:wrap;gap:calc(12*var(--u)) calc(28*var(--u));margin-top:calc(20*var(--u))}
.links button,.links a{background:none;color:var(--paper);padding:0 0 calc(4*var(--u));font-size:calc(11*var(--u));letter-spacing:.22em;text-transform:uppercase;font-weight:500;border-bottom:1px solid var(--red)}
.links button:hover,.links a:hover{background:none;color:var(--red)}
.chnav{display:flex;border-top:1px solid transparent}
.chnav a{flex:1;position:relative;padding-top:calc(12*var(--u));font-weight:500;font-size:calc(11*var(--u));letter-spacing:.16em;color:var(--grey);min-width:0}
.chnav em{display:block;margin-top:calc(4*var(--u));font-style:normal;font-size:calc(9*var(--u));letter-spacing:.12em;text-transform:uppercase;opacity:0;transition:opacity .2s;white-space:nowrap}
.chnav a:hover{color:var(--paper)}
.chnav a:hover em{opacity:1}
.chnav a.cur{color:var(--paper)}
.chnav a.cur em{opacity:1;color:var(--red)}
.chnav a.cur::before{display:none}
.stage{position:relative;overflow:hidden;background:#000;touch-action:pan-y;cursor:pointer;transition:opacity .35s ease}
.stage.dim{opacity:0}
.slide{position:absolute;inset:0;opacity:0;transition:opacity .8s ease}
.slide.on{opacity:1;z-index:2}
.slide.prev{opacity:1;z-index:1;transition:none}
.slide img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transform:scale(var(--z,1));opacity:0;transition:opacity 1.1s ease;pointer-events:none;user-select:none}
.slide img.fit{object-fit:contain}
.slide img.on{opacity:1}
.slide.on img.on{animation:kb 11s ease-out forwards}
@keyframes kb{from{transform:scale(calc(var(--z,1) * 1.03))}to{transform:scale(var(--z,1))}}
.editing .slide.on img.on{animation:none}
.editing .stage{cursor:move}
.ebar{position:fixed;top:calc(100*var(--u));right:var(--pad);z-index:50;display:flex;flex-wrap:wrap;gap:calc(8*var(--u)) calc(16*var(--u));align-items:center;max-width:56vw;background:rgba(0,0,0,.88);border:1px solid var(--red);padding:calc(10*var(--u)) calc(14*var(--u));font-size:calc(11*var(--u));letter-spacing:.1em;text-transform:uppercase}
.ebar b{color:var(--red);font-weight:500}
.ebar span{color:var(--grey)}
.ebar i{font-style:normal;text-transform:none;letter-spacing:.04em;color:var(--paper)}
.ebar button{padding:calc(8*var(--u)) calc(14*var(--u));font-size:calc(11*var(--u))}
.slide .pend{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--grey);font-size:calc(12*var(--u));letter-spacing:.24em;text-transform:uppercase;border:1px dashed #262626;margin:calc(40*var(--u))}
.scredit{position:absolute;left:calc(18*var(--u));bottom:calc(14*var(--u));z-index:4;font-size:calc(11*var(--u));letter-spacing:.14em;text-transform:uppercase;color:var(--paper);opacity:0;transition:opacity .4s;text-shadow:0 0 calc(8*var(--u)) #000}
.scredit.on{opacity:.75}
.va{position:fixed;inset:0;z-index:60;background:rgba(0,0,0,.97);display:none;overflow:auto;padding:calc(100*var(--u)) var(--pad) calc(60*var(--u))}
.va.open{display:block}
.vah{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:calc(24*var(--u))}
.vah h3{font-size:calc(20*var(--u))}
.vah button,.vab .x{background:none;color:var(--paper);padding:0 0 calc(4*var(--u));font-size:calc(11*var(--u));letter-spacing:.22em;border-bottom:1px solid var(--red)}
.vah button:hover,.vab .x:hover{background:none;color:var(--red)}
.vag{display:grid;grid-template-columns:repeat(auto-fill,minmax(calc(200*var(--u)),1fr));gap:calc(10*var(--u))}
.vag button{aspect-ratio:4/3;padding:0;background:#0b0b0b;border:1px solid #1d1d1d;cursor:zoom-in}
.vag button:hover{border-color:var(--red);background:#0b0b0b}
.vag img{width:100%;height:100%;object-fit:contain}
.vab{position:fixed;inset:0;z-index:70;background:#000;display:none;align-items:center;justify-content:center}
.vab.open{display:flex}
.vab img{max-width:92vw;max-height:84vh;object-fit:contain}
.vab .x{position:absolute;top:calc(30*var(--u));right:var(--pad)}
.vab .pv,.vab .nx{position:absolute;top:50%;width:calc(46*var(--u));height:calc(46*var(--u));border:1px solid #333;padding:0;font-size:calc(18*var(--u));letter-spacing:0;background:none;color:var(--paper)}
.vab .pv:hover,.vab .nx:hover{border-color:var(--red);color:var(--red);background:none}
.vab .pv{left:var(--pad)}.vab .nx{right:var(--pad)}
.vab .vcr{position:absolute;left:var(--pad);bottom:calc(24*var(--u));font-size:calc(11*var(--u));letter-spacing:.14em;text-transform:uppercase;color:var(--grey)}
@media(max-width:820px){
/* the page itself scrolls (not a box inside the window): in Safari a nested scroller makes the swipe stop at its end and need a second swipe to go on */
html,body{height:auto}
body{overflow:visible}
.ch{position:static;display:flex;flex-direction:column;padding-top:calc(76*var(--u));min-height:100vh;min-height:100svh}
.stage{order:-1;height:auto;aspect-ratio:3/2;flex:none}
.scredit{top:calc(12*var(--u));bottom:auto;left:calc(14*var(--u));font-size:calc(9*var(--u))}
.vov{bottom:calc(12*var(--u));padding:calc(7*var(--u)) calc(12*var(--u));font-size:calc(10*var(--u))}
.sarr{width:calc(56*var(--u));padding:0 calc(14*var(--u));font-size:calc(18*var(--u))}
.panel{border-right:0;overflow:visible}
.pbody{overflow:visible}
.chnav{flex-wrap:wrap}
}
@media(prefers-reduced-motion:reduce){
*{animation:none!important;transition:none!important}
.reveal>span{transform:none}.rule{transform:none}.lede{opacity:1}
}

.ctl{margin-top:calc(16*var(--u))}
.ctl .bar{margin-left:0}
.sarr{position:absolute;top:0;bottom:0;z-index:5;width:clamp(calc(64*var(--u)),9%,calc(120*var(--u)));display:flex;align-items:center;padding:0 calc(22*var(--u));border:0;color:var(--paper);font-size:calc(22*var(--u));letter-spacing:0;font-weight:300;opacity:.4;transition:opacity .25s,color .25s}
.sarr.l{left:0;justify-content:flex-start;background:linear-gradient(90deg,rgba(0,0,0,.35),rgba(0,0,0,0))}
.sarr.r{right:0;justify-content:flex-end;background:linear-gradient(270deg,rgba(0,0,0,.35),rgba(0,0,0,0))}
.stage:hover .sarr{opacity:.85}
.sarr:hover{opacity:1;color:var(--red)}
.sarr.l:hover{background:linear-gradient(90deg,rgba(0,0,0,.5),rgba(0,0,0,0))}
.sarr.r:hover{background:linear-gradient(270deg,rgba(0,0,0,.5),rgba(0,0,0,0))}
@media(hover:none){.sarr{opacity:.7}}

.vov{position:absolute;left:50%;bottom:calc(18*var(--u));transform:translateX(-50%);z-index:6;padding:calc(9*var(--u)) calc(16*var(--u));background:rgba(0,0,0,.55);border:1px solid rgba(239,238,238,.28);color:var(--paper);font-size:calc(11*var(--u));letter-spacing:.22em;font-weight:500;text-transform:uppercase;white-space:nowrap;opacity:.75;transition:opacity .25s,border-color .25s,color .25s}
.stage:hover .vov{opacity:1}
.vov:hover{background:rgba(0,0,0,.7);border-color:var(--red);color:var(--red)}

.editing .slide img.hid.on{opacity:.28}
.editing .slide.on img.hid.on{animation:none}

.pfoot{display:flex;flex-direction:column}
.pfoot .dots{order:1}
.pfoot .ctl{order:2}
.pfoot .chnav{order:3}
.pfoot .links{order:4;margin-top:calc(22*var(--u))}

.ch .label:empty{display:none}
.ch .label:empty+h2{margin-top:0}

/* ===== TYPE SYSTEM for chapter pages ===== */
.ch h2{font-size:clamp(calc(22*var(--u)),2vw,calc(34*var(--u)));line-height:1.05;font-weight:700}
.cap h4{font-weight:500;font-size:clamp(calc(16*var(--u)),1.2vw,calc(18*var(--u)));line-height:1.2;letter-spacing:.04em}
.lede,.cap .line{font-size:var(--t-body);line-height:1.7;font-weight:400;color:var(--c-text)}
.back,.idx,.links button,.links a,.chnav a,.ch .label,.vah button,.vab .x,.vab .vcr,.slide .pend,.scredit,.vov{font-size:var(--t-label);letter-spacing:var(--ls-caps);font-weight:500}
.chnav em{font-size:var(--t-label);letter-spacing:.08em}
.counter small{letter-spacing:var(--ls-caps)}
@media(max-width:820px){.scredit,.vov{font-size:var(--t-label);letter-spacing:.12em}.chnav a{letter-spacing:.12em}}

.idx[data-ch]::before{content:attr(data-ch) ' \00b7  '}

/* ===== 360 VIEWER (chapter option v360, see deck.js) ===== */
.stage.has360{cursor:ew-resize}
.stage.has360 .sarr,.stage.has360 .vov{display:none}
.v360{position:absolute;inset:0;z-index:3;background:#000;touch-action:pan-y;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.v360-cv{position:absolute;inset:0;width:100%;height:100%;display:block}
.v360-vid{position:absolute;left:0;top:0;width:2px;height:2px;opacity:.01;pointer-events:none}
.v360-hint{position:absolute;left:50%;bottom:calc(18*var(--u));transform:translateX(-50%);font-size:var(--t-label);letter-spacing:var(--ls-caps);font-weight:500;text-transform:uppercase;color:var(--paper);opacity:.7;white-space:nowrap;text-shadow:0 0 calc(8*var(--u)) #000;transition:opacity 1.6s ease;pointer-events:none}
.v360-hint.off{opacity:0}
@media(max-width:820px){.v360-hint{bottom:calc(12*var(--u))}}

/* ===== GALLERY LAYOUT: main picture in its original proportions, thumbnail strip glued to the bottom ===== */
.stage{display:flex;flex-direction:column;cursor:default}
.smain{flex:1;min-height:0;position:relative}
.editing .smain{position:absolute;inset:0}
body:not(.editing) .vov{display:none}
body:not(.editing) .slide{inset:calc(20*var(--u)) calc(24*var(--u)) calc(8*var(--u))}
body:not(.editing) .slide img{object-fit:contain!important;object-position:50% 50%!important;transform:none!important;filter:none!important;animation:none!important}
body:not(.editing) .scredit{top:calc(14*var(--u));bottom:auto}
.thumbs{flex:none;display:flex;flex-wrap:wrap;justify-content:center;gap:calc(8*var(--u));padding:calc(12*var(--u)) calc(24*var(--u)) calc(20*var(--u))}
.th{position:relative;flex:none;width:clamp(calc(64*var(--u)),6vw,calc(120*var(--u)));aspect-ratio:16/9;padding:0;border:0;background:#0b0b0b;overflow:hidden;cursor:pointer;letter-spacing:0}
.th:hover{background:#0b0b0b}
.th img{display:block;width:100%;height:100%;object-fit:cover;filter:grayscale(1);opacity:.7;transition:filter .85s cubic-bezier(.65,0,.25,1),opacity .85s cubic-bezier(.65,0,.25,1);pointer-events:none;user-select:none;-webkit-user-drag:none}
.th::after{content:'';position:absolute;left:0;right:0;bottom:0;height:2px;background:var(--red);transform:scaleX(0);transform-origin:left;transition:transform .35s ease}
.th.on img{filter:none;opacity:1}
.th.on::after{transform:none}
@media(hover:hover){.th:hover img{filter:none;opacity:1}}
.th:focus-visible{outline:1px solid var(--red);outline-offset:2px}
/* the small slide bars are gone (the thumbnails do that job); the red rule under the chapter number now shows progress through the chapters */
.pfoot .dots,.pfoot .ctl{display:none}
/* text column scroll bar: see the site-wide iOS-style bar in site.css */
@media(max-width:820px){
.stage{aspect-ratio:auto;display:block}
.smain{aspect-ratio:3/2;flex:none}
body:not(.editing) .slide{inset:0}
.thumbs{padding:calc(10*var(--u)) calc(14*var(--u)) calc(14*var(--u));gap:calc(6*var(--u))}
.th{width:calc(25% - calc(5*var(--u)))}
}

/* quick, parallel cross-fade: the old picture leaves while the new one arrives */
body:not(.editing) .slide{transition:opacity .55s ease}
body:not(.editing) .slide.prev{opacity:0;transition:opacity .55s ease}
body:not(.editing) .slide img{transition:opacity .55s ease}
/* invisible side zones on the main picture: click the left side for the previous image, the right side for the next */
.smain>.sarr{display:block;width:32%;padding:0;opacity:0!important;background:none!important;border:0;font-size:0;cursor:default}
.smain>.sarr:hover,.smain>.sarr:focus{background:none!important;opacity:0!important}
.stage.has360 .smain>.sarr{display:none}

/* pinned header with the chapter progress rule (1/4, 2/4, 3/4, 4/4) */
.phead{flex:none}
.phead .rule{transform:none;margin:calc(22*var(--u)) 0 0;width:0;transition:width .8s cubic-bezier(.7,0,.2,1)}
.go .phead .rule{animation:none}
.pbody{padding-top:calc(18*var(--u))}
@media(max-width:820px){.pbody{padding-top:calc(18*var(--u))}}
/* the invisible side zones get a red chevron cursor (the same thin chevron as the scroll arrow) */
.smain>.sarr.l{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cpath d='M19 5 L12 16 L19 27' fill='none' stroke='%23000' stroke-opacity='.45' stroke-width='6' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M19 5 L12 16 L19 27' fill='none' stroke='%23FF2800' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 16 16,w-resize}
.smain>.sarr.r{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cpath d='M13 5 L20 16 L13 27' fill='none' stroke='%23000' stroke-opacity='.45' stroke-width='6' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M13 5 L20 16 L13 27' fill='none' stroke='%23FF2800' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 16 16,e-resize}

/* the red marker over the chapter numbers is one bar that stretches toward the next chapter and then lets its tail catch up */
.chnav{position:relative}
.chmark{position:absolute;top:-1px;height:2px;background:var(--red);pointer-events:none;transition:left .6s cubic-bezier(.65,0,.25,1),right .6s cubic-bezier(.65,0,.25,1)}
.chmark.mfwd{transition-delay:.16s,0s}
.chmark.mback{transition-delay:0s,.16s}
.chmark.init{transition:none}
@media(max-width:820px){
/* phone order: chapter number and the first text, then the picture or model, then the caption text, then navigation */
.panel,.pbody{display:contents}
.phead{order:1;margin:0 var(--pad);padding-top:calc(12*var(--u))}
.pbody>*{order:2;margin-left:var(--pad);margin-right:var(--pad)}
.stage{order:3;margin-top:calc(28*var(--u))}
.pbody>.cap{order:4}
.pfoot{order:5;margin:calc(30*var(--u)) var(--pad) 0}
}


/* ===== Project header (all screens): no "back" link, chapter number left + title right on one line, progress rule across the full width, label left / text right ===== */
.back{display:none}
.phead{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:end;column-gap:calc(18*var(--u))}
.phead .chnum{grid-column:1;grid-row:1;min-height:calc(42*var(--u));display:flex;align-items:flex-end}
.ptitle{grid-column:2;grid-row:1;display:flex;align-items:flex-end;justify-content:flex-end;min-height:calc(42*var(--u));text-align:right;font-weight:700;font-size:clamp(calc(19*var(--u)),1.45vw,calc(26*var(--u)));line-height:1.12;letter-spacing:.01em;text-transform:uppercase;color:var(--paper)}
.ptitle .reveal{text-align:right}
.phead .rule{grid-column:1/-1;grid-row:2;margin-top:calc(16*var(--u))}
.ptext{display:grid;grid-template-columns:34% minmax(0,1fr);column-gap:calc(14*var(--u));align-items:baseline;margin-top:calc(14*var(--u))}
.ptext>.label{grid-column:1;margin:0;line-height:1.7}
.ptext>h2{display:none}
.ptext>.lede{grid-column:2;margin:0;text-align:right;max-width:none}
/* long chapter text would turn into a very tall narrow column: the label sits on its own line and the text runs full width */
.ptext.long{grid-template-columns:minmax(0,1fr);row-gap:calc(12*var(--u))}
.ptext.long>.label,.ptext.long>.lede{grid-column:1}
.ptext.long>.lede{text-align:left}
.ptext.long>.label:empty{display:none}
.cap{border-top:0;padding-top:0;margin-top:calc(30*var(--u))}
@media(max-width:820px){
.phead{padding-top:calc(14*var(--u))}
.ptext{order:2;margin:calc(28*var(--u)) var(--pad) 0}
}

/* ===== Next chapter / next project as a red button (same shape as "Send" on the contact page) ===== */
.pfoot .links{height:auto;overflow:visible;margin-top:calc(22*var(--u))}
.pfoot .links button{display:inline-block;background:var(--line);color:#fff;border:0;padding:calc(14*var(--u)) calc(30*var(--u));font-size:calc(12*var(--u));letter-spacing:.22em;transition:background .2s,color .2s}
.pfoot .links button:hover{background:var(--red);color:#000}

/* ===== PANORAMA (slide option pano, see deck.js) ===== */
.stage.has-pano .smain>.sarr{display:none}
.pano{position:absolute;inset:0;z-index:3;background:#000;overflow:hidden;touch-action:pan-y;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}
.pano-poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:opacity .7s ease;pointer-events:none}
.pano-cv{position:absolute;inset:0;width:100%;height:100%;display:block;opacity:0;transition:opacity .7s ease}
.pano.ready .pano-cv{opacity:1}
.pano.ready .pano-poster{opacity:0}
.pano-hint{position:absolute;left:50%;bottom:calc(18*var(--u));transform:translateX(-50%);font-size:var(--t-label);letter-spacing:var(--ls-caps);font-weight:500;text-transform:uppercase;color:rgba(239,238,238,.85);text-shadow:0 0 8px rgba(0,0,0,.6);white-space:nowrap;pointer-events:none;transition:opacity 1.6s ease;z-index:2}
.pano-hint.off{opacity:0}
.pano-btns{display:none;position:absolute;right:calc(12*var(--u));top:calc(12*var(--u));gap:calc(8*var(--u));z-index:4}
.pano.touch .pano-btns{display:flex}
.pano-btn{padding:calc(7*var(--u)) calc(12*var(--u));background:rgba(0,0,0,.5);border:1px solid rgba(239,238,238,.28);color:var(--paper);font:inherit;font-size:var(--t-label);letter-spacing:.14em;font-weight:500;text-transform:uppercase;white-space:nowrap;cursor:pointer;transition:border-color .25s,color .25s}
.pano-btn[hidden]{display:none}
.pano-btn.on{border-color:var(--red);color:var(--red)}
@media(max-width:820px){.pano-hint{bottom:calc(12*var(--u))}}

/* ===== Desktop project page, second layout pass (patch 30) ===== */
.smain{user-select:none;-webkit-user-select:none;-webkit-user-drag:none}
/* the picture changes over a black layer, so the frame of the picture that is leaving never shows beside a narrower one that is arriving */
body:not(.editing) .slide.on{background:#000}
.smain{overflow:hidden}
@media(min-width:821px){
/* title left, chapter number right, label under the rule on the right, text below on the left */
.phead{grid-template-columns:minmax(0,1fr) auto;grid-template-rows:calc(46*var(--u)) auto auto;padding-top:calc(4*var(--u))}
.phead .chnum{grid-column:2;grid-row:1}
/* the title is pinned by its last line to the number's baseline, so the number never jumps; a second line grows upward */
.ptitle{align-self:end;position:relative;height:calc(46*var(--u));min-height:0}
.ptitle .reveal{position:absolute;left:0;right:0;bottom:0}
/* the label sits right above the progress rule, on the right */
.plab{display:block;grid-column:1/-1;grid-row:2;text-align:right;margin-top:calc(6*var(--u));margin-bottom:calc(10*var(--u));line-height:1.3}
.plab:empty{display:none}
.phead .rule{grid-row:3;margin-top:0}
.panel{overflow:visible}
.ptitle{grid-column:1;justify-content:flex-start;text-align:left;font-size:clamp(calc(22*var(--u)),1.9vw,calc(34*var(--u)));line-height:1.08;text-transform:uppercase}
.ptitle .reveal{text-align:left}
.ptext,.ptext.long{grid-template-columns:minmax(0,1fr);margin-top:calc(8*var(--u))}
.ptext>.label,.ptext.long>.label{display:none}
.ptext>.lede,.ptext.long>.lede{grid-column:1;grid-row:1;text-align:left;max-width:74%}
/* the vertical divider stops as far above the bottom of the page as it starts below the header */
.panel{border-right:0;position:relative}
.panel::after{content:'';position:absolute;right:0;top:0;bottom:calc(112*var(--u));width:1px;background:var(--line);pointer-events:none}
/* Next chapter / Next project: grey button, as wide as one chapter cell and right-aligned under the last one */
.pfoot .links{justify-content:flex-end}
.pfoot .links button{width:calc(100% / var(--n,4));padding:calc(14*var(--u)) calc(8*var(--u));text-align:center;white-space:normal;letter-spacing:.16em;line-height:1.5}
}

/* ===== Desktop: the lower block (chapter numbers, Next button, thumbnails) sits about two lines higher off the page edge ===== */
@media(min-width:821px){
.pfoot{padding-bottom:calc(60*var(--u))}
.thumbs{padding-bottom:calc(54*var(--u))}
}
@media(max-width:820px){.plab{display:none}}

/* all screens: the title is pinned by its last line, a second line grows upward, so the chapter number never moves */
.ptitle{align-self:end;position:relative;height:calc(42*var(--u));min-height:0}
.ptitle .reveal{position:absolute;left:0;right:0;bottom:0}
@media(min-width:821px){.ptitle{height:calc(46*var(--u))}}

/* ===== Patch 33 ===== */
/* Next chapter / Next project: the triangle replaces the arrow; the button is exactly one chapter cell wide (same as the red marker above it) */
.pfoot .links button::after{content:'';display:inline-block;width:calc(7*var(--u));height:calc(8*var(--u));margin-left:calc(10*var(--u));background:currentColor;clip-path:polygon(0 0,100% 50%,0 100%);vertical-align:baseline}
/* the last chapter's button leads to the next project: red with black text, white on hover */
.pfoot .links button.proj{background:var(--red);color:#000}
.pfoot .links button.proj:hover{background:#fff;color:#000}
@media(min-width:821px){
.pfoot .links button{box-sizing:border-box;font-size:clamp(calc(8.5*var(--u)),.72vw,calc(11*var(--u)));letter-spacing:.1em;padding:calc(14*var(--u)) calc(4*var(--u))}
.pfoot .links button::after{margin-left:calc(6*var(--u))}
}
/* the interior panorama keeps its picture pushed to the right edge (the ordinary photos stay centred) */
body:not(.editing) .slide:has(.pano){inset:calc(20*var(--u)) 0 calc(8*var(--u)) calc(24*var(--u))}

/* chapter names under the numbers are always visible, dark grey; lighter on hover, red for the current chapter */
.chnav em{opacity:1;color:#555;transition:color .2s}
.chnav a:hover em{color:var(--grey)}
.chnav a.cur em,.chnav a.cur:hover em{color:var(--red)}
@media(max-width:600px){.chnav em{font-size:calc(8.5*var(--u));letter-spacing:.02em;overflow:hidden;text-overflow:ellipsis}}

/* ===== Phone project page, tightening pass (patch 101) =====
   - the chapter label (red) sits right under the chapter number, above the rule, as on desktop; the title is pinned by its last line to the number's baseline, so a second line grows upward
   - the chapter text runs the full width, left aligned
   - the chapter bar with the numbers and the Next button sit right under the gallery, the picture caption follows */
@media(max-width:820px){
.phead{grid-template-rows:auto auto auto;padding-top:calc(4*var(--u))}
.phead .chnum{grid-column:1;grid-row:1}
.ptitle{grid-column:2;grid-row:1;align-self:end;position:relative;height:calc(42*var(--u));min-height:0}
.ptitle .reveal{position:absolute;left:0;right:0;bottom:0;text-align:right}
.plab{display:block;grid-column:1/-1;grid-row:2;text-align:left;margin-top:calc(6*var(--u));margin-bottom:calc(10*var(--u));line-height:1.3}
.plab:empty{display:none}
.phead .rule{grid-row:3;margin-top:0}
.ptext,.ptext.long{grid-template-columns:minmax(0,1fr);margin-top:calc(18*var(--u))}
.ptext>.label,.ptext.long>.label{display:none}
.ptext>.lede,.ptext.long>.lede{grid-column:1;grid-row:1;text-align:left;max-width:none}
}

/* ===== Gallery, thumbnails, soft automatic fade, phone page order (patch 102) ===== */
/* thumbnails: a grid whose rows start at the left (the last row is not centred); the whole grid stays centred under the picture */
.thumbs{position:relative;overflow:hidden;display:grid;grid-template-columns:repeat(auto-fill,clamp(calc(64*var(--u)),6vw,calc(120*var(--u))));justify-content:center}
.th{width:100%}
.th::after,.th.on::after{display:none}
/* the red line under the current thumbnail travels from one to the next (deck.js: placeBar) */
.thbar.hov{z-index:3}
.thbar{position:absolute;left:0;top:0;width:0;height:2px;background:var(--red);pointer-events:none;z-index:2;transition:left .85s cubic-bezier(.65,0,.25,1),width .85s cubic-bezier(.65,0,.25,1),opacity .3s ease}
/* automatic change of pictures: slower, smoother cross-fade (the incoming picture fades in over the outgoing one, which stays until the end) */
body:not(.editing) .stage.autofade .slide{transition:opacity 1.2s ease-in-out}
body:not(.editing) .stage.autofade .slide.prev{opacity:1;transition:none}
body:not(.editing) .stage.autofade .slide img.on{transition:opacity 1.2s ease-in-out;z-index:1}
body:not(.editing) .stage.autofade .slide img:not(.on){transition:opacity .8s ease-in-out .4s}
@media(max-width:820px){
/* gallery: one fixed height on every chapter, set by the most vertical picture of the project (--galr is written by build.py) */
.smain{aspect-ratio:var(--galr,1.5)!important}
.thumbs{grid-template-columns:repeat(4,minmax(0,1fr));justify-content:stretch;gap:calc(6*var(--u));padding:calc(10*var(--u)) 0 calc(6*var(--u))}
.th{width:100%}
/* order: gallery, thumbnails, chapter numbers, picture caption, chapter text, Next button at the very bottom on the right */
.pfoot{display:contents}
.pfoot .chnav{order:4;margin:calc(2*var(--u)) var(--pad) 0}
.pbody>.cap{order:5;margin-top:calc(16*var(--u))}
.pbody>.ptext{order:6;margin-top:calc(22*var(--u))}
.pfoot .links{order:7;margin:calc(26*var(--u)) var(--pad) calc(48*var(--u));justify-content:flex-end}
.pfoot .links button{width:auto;min-width:calc(150*var(--u));padding:calc(14*var(--u)) calc(24*var(--u)) calc(14*var(--u)) calc(22*var(--u))}
.ptext,.ptext.long{text-align:justify}
.ptext>.lede,.ptext.long>.lede,.cap .line{text-align:justify;text-justify:inter-word;-webkit-hyphens:auto;hyphens:auto}
}
@media(max-width:820px){body:not(.editing) .slide:has(.pano){inset:0}}


/* Click to zoom label over the bottom of an ordinary gallery picture (same line and look as the panorama label) */
.zoom-hint{position:absolute;left:50%;bottom:calc(18*var(--u));transform:translateX(-50%);font-size:var(--t-label);letter-spacing:var(--ls-caps);font-weight:500;text-transform:uppercase;color:rgba(239,238,238,.85);text-shadow:0 0 5px rgba(0,0,0,.95),0 0 12px rgba(0,0,0,.85),0 0 22px rgba(0,0,0,.6);white-space:nowrap;pointer-events:none;transition:opacity 1.6s ease;z-index:4}
.zoom-hint.off{opacity:0}
.stage.has-pano .zoom-hint,.stage.has360 .zoom-hint{display:none}
@media(max-width:820px){.zoom-hint{display:none}}

/* no native picture dragging or selecting anywhere in the gallery, the big viewer and the thumbnails */
.stage img,.stage canvas,.stage video,.vab img,.vag img,.thumbs img{-webkit-user-drag:none;user-select:none;-webkit-user-select:none}
.stage,.vab{-webkit-touch-callout:none}

/* while the picture is held zoomed, the cursor is a small white dot (5 px), like a point of gaze */
.stage.zooming,.stage.zooming *{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='7' viewBox='0 0 7 7'%3E%3Ccircle cx='3.5' cy='3.5' r='2.5' fill='%23fff' stroke='%23000' stroke-opacity='.28' stroke-width='1'/%3E%3C/svg%3E") 3 3,default!important}

/* ===== Next chapter / Next project: the hover colour fills the button from left to right in 0.8 s, and on leaving it runs back to the left, the same way (patch 123) ===== */
.pfoot .links button{background-color:var(--line);background-image:linear-gradient(var(--red),var(--red));background-repeat:no-repeat;background-size:0% 100%;background-position:left center;transition:background-size .8s ease,color .8s ease}
.pfoot .links button.proj{background-color:var(--red);background-image:linear-gradient(#fff,#fff);background-repeat:no-repeat;background-size:0% 100%;background-position:left center}
@media(hover:hover){
.pfoot .links button:hover{background-color:var(--line);background-image:linear-gradient(var(--red),var(--red));background-size:100% 100%;background-position:left center;background-repeat:no-repeat;color:#000}
.pfoot .links button.proj:hover{background-color:var(--red);background-image:linear-gradient(#fff,#fff);background-size:100% 100%;background-position:left center;background-repeat:no-repeat;color:#000}
}

/* Patch 130: the same 0.22 s colour fade on the project pages (back arrow, chapter names, slide arrows) */
.back,.sarr{transition:opacity .22s ease,color .22s ease}
.chnav em{transition:color .22s ease}

/* patch 182: phone gallery frame height written by deck.js (--galh) so the chapter numbers end two lines above the bottom edge of the screen */
@media(max-width:820px){.ch[style*='--galh'] .smain{aspect-ratio:auto!important;height:var(--galh)}}

/* patch 182: panorama on phones: the middle 30% of the height only turns the camera (any direction); above and below it vertical swipes scroll the page */
.pano-mid{position:absolute;left:0;right:0;top:35%;height:30%;z-index:2;touch-action:none}
@media(hover:hover) and (pointer:fine){.pano-mid{display:none}}

/* patch 190: phone gallery: when the chapter numbers would sit too low, the thumbnails get smaller (deck.js sets --thc, the number of thumbnails per row) */
@media(max-width:820px){.ch[style*='--thc'] .thumbs{grid-template-columns:repeat(var(--thc),minmax(0,1fr))}}

/* patch 201: every change of picture: the old one fades out to the dark (0.42 s), then the next one comes in (0.62 s) - never both at once */
body:not(.editing) .stage.dip .slide.prev{opacity:0;transition:opacity .42s ease-in-out}
body:not(.editing) .stage.dip .slide.on{transition:opacity .62s ease-in-out .44s}
body:not(.editing) .stage.dipi .slide img{transition:opacity .42s ease-in-out}
body:not(.editing) .stage.dipi .slide img.on{transition:opacity .62s ease-in-out .44s}

/* ===== patch 203: the light film player (see deck.js, vpMake) ===== */
.vplay{position:absolute;inset:0;z-index:3;opacity:0;pointer-events:none;cursor:pointer;transition:opacity .55s ease;-webkit-tap-highlight-color:transparent}
.vplay.on{opacity:1;pointer-events:auto}
.vplay video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;display:block;background:transparent}
body:not(.editing) .stage.dipi .vplay{transition:opacity .42s ease-in-out}
body:not(.editing) .stage.dipi .vplay.on{transition:opacity .62s ease-in-out .44s}
.stage.has-video .zoom-hint{display:none}
/* the control pill: quiet glass, four controls, fades away while the film plays */
.vpill{position:absolute;left:50%;bottom:calc(18*var(--u));transform:translateX(-50%);z-index:6;display:flex;align-items:center;gap:calc(2*var(--u));padding:calc(4*var(--u)) calc(10*var(--u));border-radius:999px;background:rgba(28,28,30,.58);-webkit-backdrop-filter:blur(22px) saturate(1.6);backdrop-filter:blur(22px) saturate(1.6);border:1px solid rgba(255,255,255,.1);cursor:default;transition:opacity .45s ease}
.vplay.idle .vpill{opacity:0;pointer-events:none}
.vb,.vb:hover,.vb:focus,.vb:active{width:calc(46*var(--u));height:calc(46*var(--u));padding:0;background:none!important;border:0;box-shadow:none;display:flex;align-items:center;justify-content:center;font-size:0;letter-spacing:0;text-transform:none;cursor:pointer;-webkit-tap-highlight-color:transparent;outline:none}
.vb{color:rgba(255,255,255,.92);transition:color .2s ease,transform .2s ease}
.vb svg{width:calc(24*var(--u));height:calc(24*var(--u));display:block;overflow:visible}
@media(hover:hover){.vb:hover{color:var(--red)}}
.vb:active{transform:scale(.9)}
.vb:focus-visible{outline:1px solid var(--red);outline-offset:calc(-4*var(--u));border-radius:50%}
.vplay.muted .vw,.vplay:not(.muted) .vx{display:none}
.vplay:not(.paused) .ia,.vplay.paused .ip{display:none}
@media(max-width:820px){.vpill{bottom:calc(10*var(--u));padding:calc(2*var(--u)) calc(6*var(--u))}.vb,.vb:hover,.vb:focus,.vb:active{width:calc(42*var(--u));height:calc(42*var(--u))}.vb svg{width:calc(22*var(--u));height:calc(22*var(--u))}}
/* thumbnail of a film: a clear round play button in the middle (patch 205: much larger than the small corner mark before) */
.th.vid::before{content:'';box-sizing:border-box;position:absolute;left:50%;top:50%;width:calc(38*var(--u));height:calc(38*var(--u));margin:calc(-19*var(--u)) 0 0 calc(-19*var(--u));border-radius:50%;background:rgba(0,0,0,.5) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 38 38'%3E%3Cpath d='M14.85 14.4v9.2L23.05 19z' fill='%23fff' stroke='%23fff' stroke-width='1.6' stroke-linejoin='round'/%3E%3C/svg%3E") center/100% 100% no-repeat;border:1px solid rgba(255,255,255,.6);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);box-shadow:0 2px 10px rgba(0,0,0,.45);z-index:2;pointer-events:none;transition:transform .22s ease,background-color .22s ease,border-color .22s ease}
@media(hover:hover){.th.vid:hover::before{transform:scale(1.1);background-color:var(--red);border-color:var(--red)}}

/* patch 203: several 360 cars in one chapter - the old one fades out first, the new one comes in after it (same rhythm as the pictures) */
.v360.out{opacity:0;pointer-events:none;animation:none;transition:opacity .42s ease-in-out}
.v360.swap{animation:v360in .62s ease-in-out .44s both}
@keyframes v360in{from{opacity:0}to{opacity:1}}
@media(prefers-reduced-motion:reduce){.v360.swap{animation:none}}

/* ===== patch 205: film timeline under the picture (grey track, red = played) with a frame preview above it ===== */
.vtl{position:absolute;z-index:7;opacity:0;pointer-events:none;transition:opacity .55s ease;touch-action:none;cursor:pointer;-webkit-tap-highlight-color:transparent;outline:none}
.vtl.on{opacity:1;pointer-events:auto}
body:not(.editing) .stage.dipi .vtl{transition:opacity .42s ease-in-out}
body:not(.editing) .stage.dipi .vtl.on{transition:opacity .62s ease-in-out .44s}
.vtl-bar{position:absolute;left:0;right:0;top:50%;height:2px;margin-top:-1px;background:rgba(255,255,255,.3);transition:height .16s ease,margin-top .16s ease}
.vtl.hot .vtl-bar,.vtl:focus-visible .vtl-bar{height:4px;margin-top:-2px}
.vtl-fill{position:absolute;left:0;top:0;right:0;bottom:0;background:var(--red);transform-origin:0 50%;transform:scaleX(0)}
.vtl-knob{position:absolute;top:50%;left:0;width:calc(13*var(--u));height:calc(13*var(--u));margin:0;border-radius:50%;background:var(--red);transform:translate(-50%,-50%) scale(0);transition:transform .16s ease;pointer-events:none}
.vtl.hot .vtl-knob,.vtl:focus-visible .vtl-knob{transform:translate(-50%,-50%) scale(1)}
.vtl-pv{position:absolute;left:0;bottom:calc(100% - 2px);width:calc(176*var(--u));transform:translateX(-50%);opacity:0;pointer-events:none;transition:opacity .14s ease;text-align:center}
.vtl.hot .vtl-pv{opacity:1}
.vtl-img{display:block;width:100%;aspect-ratio:16/9;box-sizing:border-box;border:1px solid rgba(255,255,255,.8);background:#111 center/cover no-repeat;box-shadow:0 4px 18px rgba(0,0,0,.55)}
.vtl-pv:not(.has) .vtl-img{display:none}
.vtl-t{display:block;margin-top:calc(6*var(--u));font-size:calc(12*var(--u));font-weight:500;letter-spacing:.04em;color:#fff;font-variant-numeric:tabular-nums;text-shadow:0 1px 6px rgba(0,0,0,.9)}
.vtl-pv:not(.has) .vtl-t{margin-bottom:calc(6*var(--u))}
.vplay.scrub .vpill{opacity:0!important;pointer-events:none}

/* patch 209: a click while another change is still running gets a quicker version of the same soft change */
body:not(.editing) .stage.dip.hurry .slide.prev{transition:opacity .2s ease-in-out}
body:not(.editing) .stage.dip.hurry .slide.on{transition:opacity .4s ease-in-out .14s}
/* big windows with the 30% text column: the Next button stays one line (see the first .ch rule) */
@media(min-width:1800px) and (min-height:800px){
.pfoot .links button{white-space:nowrap;font-size:calc(9.4*var(--u));letter-spacing:.05em;padding:calc(15*var(--u)) calc(2*var(--u))}
.pfoot .links button::after{margin-left:calc(5*var(--u))}
}

/* Phones and narrow tablets: every case study picture is shown whole (fit), never cropped (Oct 2026) */
@media(max-width:820px){.stage .slide img{transform:none!important}}

/* crop mode on a phone-sized window: a slim bar at the very top */
@media(max-width:820px){.ebar{top:0!important;bottom:auto!important;left:0!important;right:0!important;padding:6px 10px!important;font-size:11px!important;display:flex;flex-wrap:wrap;gap:4px 10px;align-items:center}.ebar span{display:none!important}}

/* desktop: projects with crop-board crops get one fixed gallery frame shape in every chapter (--hlfr, set by phone-crop-lib.js) */
@media(min-width:821px){.ch.hlfr .smain{flex:none!important;aspect-ratio:var(--hlfr)!important;height:auto!important;max-height:calc(100svh - 220px)}}

/* touch swipe (Oct 21): while a swipe hands over to the next picture, the usual fades are switched off so nothing flickers */
.stage.swiping .slide,.stage.swiping .slide img{transition:none!important}
