/* renascentia.dev
   Page colour is the median edge colour of the chalk canvases
   (see image-manifest.json). One accent: bronze. One corner: square.

   One bronze line runs through the whole page. It starts as the horizon under
   the opening panorama, goes down one side of the screen, crosses each stage,
   goes down the other side, and so on: the level that raises each landmark,
   the thread the inventions hang on. At the end it splits in two, one branch
   into each door. Every piece of it is drawn by .line (or a ::before/::after
   named below) and all of them are 2px of --bronze. */

@font-face{font-family:Instrument;src:url("assets/fonts/instrument-serif.woff2") format("woff2");font-display:swap}
@font-face{font-family:Instrument;src:url("assets/fonts/instrument-serif-italic.woff2") format("woff2");font-style:italic;font-display:swap}
/* Georgia cut to Instrument Serif's width, so the swap does not move the page. */
@font-face{font-family:"Instrument Fallback";src:local("Georgia");size-adjust:81%;ascent-override:118%;descent-override:36%;line-gap-override:0%}

/* Scroll numbers. Registered so a scroll-driven animation can interpolate
   them. The initial values are the finished, static page.
     --p  0 to 1 across the pinned part of a .pin section
     --t  0 to 1 while a chapter line crosses the screen
     --g  0 to 1 down the whole page
   --g is not inherited. Only the header and the page grid use it, and each of
   them is given it directly (see "page progress" below). If it were inherited
   from <html>, every element on the page would be restyled on every frame. */
@property --p{syntax:"<number>";inherits:true;initial-value:1}
@property --t{syntax:"<number>";inherits:true;initial-value:.5}
@property --g{syntax:"<number>";inherits:false;initial-value:0}

:root{
  --page:#1c1b1a;
  --ink:#ece7db;
  --ink-dim:#a9a397;
  --rule:rgba(236,231,219,.16);
  --bronze:#b98d54;
  --display:Instrument,"Instrument Fallback",Georgia,"Times New Roman",serif;
  --text:Georgia,"Times New Roman",serif;
  --label:"Courier New",Courier,monospace;
  --side:max(4vw,calc(env(safe-area-inset-left) + 12px),calc(env(safe-area-inset-right) + 12px));
  --hdr:52px;                    /* height of the header bar */
  --lw:2px;                      /* weight of the bronze line */
  /* where the line runs down each side of the screen */
  --gl:max(8px,calc(env(safe-area-inset-left) + 6px),1.8vw);
  --gr:max(8px,calc(env(safe-area-inset-right) + 6px),1.8vw);
  --hold:1;                      /* pinned distances are multiplied by this; shorter on phones */
  /* The two doors close the page as a pair across the whole content width. */
  --wrap:max(1512px,125svh);     /* widest the page content gets; wider on a tall, wide screen */
  --dgap:clamp(24px,3vw,48px);
  --dw:calc((min(100vw - 2 * var(--side),var(--wrap)) - var(--dgap)) / 2);

  /* Canvas state. These defaults are the finished, static page. */
  --u:1;      /* how far the line and the painting have risen, 0 = ground, 1 = top */
  --c:1;      /* how much chalk shows, from the ground up (pyramid) */
  --q:1;      /* how far a sideways, spreading or opening painting has got */
  --rev:1;    /* painting opacity (inventions) */
  --tilt:0;   /* degrees the sheet lies back (pyramid) */
  --m:.5;     /* camera travel, 0 = start, 1 = end */
  --zk:1;     /* camera scale */

  /* Header. scroll.js replaces these with measured page positions. */
  --h0:.03;--hd:.01;
}

*{box-sizing:border-box}
html{background:var(--page);-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{margin:0;color:var(--ink);font:17px/1.55 var(--text);overflow-x:clip}
h1,h2,h3,p,figure,ul{margin:0}
ul{padding:0;list-style:none}
h1,h2,h3{font-family:var(--display);font-weight:400;font-synthesis:none}
a{color:inherit;text-decoration:none}
img{display:block}
em{font-style:italic;color:var(--bronze)}
.wrap{width:min(calc(100% - 2 * var(--side)),var(--wrap));margin-inline:auto}
:focus-visible{outline:2px solid var(--bronze);outline-offset:3px}
.skip{position:fixed;top:-6rem;left:1rem;padding:.75rem 1rem;background:var(--ink);color:var(--page);z-index:6}
.skip:focus{top:calc(1rem + env(safe-area-inset-top))}
/* Whatever focus or the skip link scrolls to stops clear of the header. */
a,#title{scroll-margin-top:calc(var(--hdr) + env(safe-area-inset-top) + 14px)}
.ne{display:inline-block;width:.5em;height:.5em;margin-left:.26em;color:var(--bronze);vertical-align:.14em;overflow:visible}

/* Layers, back to front: grid -1, page 0, header 4, skip link 6. */

/* ---------- page progress ----------
   --g is used by the page grid (body::before), the header, its chapter names
   and its rail, and each of them is given it directly: by a scroll-driven
   animation of its own (see "Driver 1"), or by scroll.js writing it on that
   element (the fallback driver, and reduced motion). Nothing inherits it,
   except the grid, which is a pseudo-element and takes it from <body>. */
body::before{--g:inherit}

/* ---------- the page-level chalk construction grid ---------- */
body::before{content:"";position:fixed;z-index:-1;left:0;right:0;top:0;height:calc(100vh + 240px);height:calc(100lvh + 240px);pointer-events:none;
  background-image:linear-gradient(rgba(236,231,219,.05) 1px,transparent 1px),linear-gradient(90deg,rgba(236,231,219,.05) 1px,transparent 1px);
  background-size:96px 96px;background-position:50% 0}
html.motion body::before{transform:translate3d(0,calc(var(--g) * -240px),0)}

/* ---------- header ----------
   Without scroll.js it is a plain bar at the top of the page. With it, the bar
   is fixed and slides in once the opening has left (--shown), and each chapter
   name shows between its two page positions --a and --b. */
.bar{position:sticky;z-index:4;top:0;left:0;right:0;padding-top:env(safe-area-inset-top);background:var(--page);
  --shown:clamp(0,calc((var(--g) - var(--h0)) / var(--hd)),1)}
html.js .bar{position:fixed;transform:translate3d(0,calc((var(--shown) - 1) * 102%),0)}
html.js .bar:focus-within{transform:none}
.bar-in{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:0 clamp(12px,2vw,28px);height:var(--hdr);
  padding-inline:max(var(--side),calc(var(--gl) + 14px)) max(var(--side),calc(var(--gr) + 14px))}
.bar-mark{display:inline-flex;align-items:center;min-height:44px;font:22px/1 var(--display);letter-spacing:-.02em;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bar-chap{position:relative;height:24px;font:italic 19px/24px var(--display);color:var(--ink-dim);text-align:center;white-space:nowrap}
.bar-chap span{position:absolute;left:0;right:0;top:0;overflow:hidden;text-overflow:ellipsis;display:none;--a:2;--b:2;
  opacity:calc(clamp(0,calc((var(--g) - var(--a)) * 700),1) * clamp(0,calc((var(--b) - var(--g)) * 700),1))}
html.js .bar-chap span{display:block}
.bar-links{display:flex;gap:clamp(4px,1.6vw,22px)}
.bar-links a{display:inline-flex;align-items:center;min-height:44px;padding-inline:6px;font:18px/1 var(--display);white-space:nowrap}
.bar-links a:hover,.bar-mark:hover{color:var(--bronze)}
/* The rail: the same bronze line, wound up along the bottom of the bar. */
.rail{display:block;height:var(--lw);background:var(--rule)}
.rail-fill{display:block;height:100%;background:var(--bronze);transform-origin:0 50%;transform:scaleX(var(--g))}

/* ---------- the bronze line ----------
   Inside a stage: .in comes down one side from the top of the stage to the
   line's height --ly, .run crosses the stage at --ly, .out goes on down the
   other side to the bottom of the stage. The stage clips what sticks out. */
.stage{position:relative;overflow:clip}
.line{position:absolute;inset:0;pointer-events:none;z-index:0}
.over .line{z-index:2}
.line i{position:absolute;background:var(--bronze)}
.line .run{left:var(--gl);right:var(--gr);top:calc(var(--lw) / -2);height:var(--lw);transform:translate3d(0,var(--ly),0)}
.line .in{top:-200vh;height:200vh;width:var(--lw);transform:translate3d(0,var(--ly),0)}
.line .out{top:0;bottom:0;width:var(--lw);transform:translate3d(0,var(--ly),0)}
.in-l .line .in{left:var(--gl)}
.in-l .line .out{right:var(--gr)}
.in-r .line .in{right:var(--gr)}
.in-r .line .out{left:var(--gl)}

/* ---------- canvas: one component for every plate ----------
   .canvas is the frame. Each .layer fills it and is clipped in frame
   coordinates; the .cam inside is the picture. The camera shows --vv of the
   picture's height, centred on (--cxx, --cyy), scaled by --zk. Both layers
   read the same variables, so chalk and paint can never part. */
.canvas{position:relative;overflow:hidden;container-type:size;width:var(--cw);height:var(--ch);background:var(--ground,var(--page));
  outline:1px solid rgba(236,231,219,.2);outline-offset:9px;box-shadow:0 26px 60px rgba(0,0,0,.4)}
.layer{position:absolute;inset:0;overflow:hidden}
.cam{--ih:calc(100cqh / var(--vv,1));--iw:calc(var(--ih) * 1.5);position:absolute;left:0;top:0;width:var(--iw);height:var(--ih);transform-origin:0 0;
  transform:translate(calc(50cqw - var(--cxx,.5) * var(--iw) * var(--zk)),calc(50cqh - var(--cyy,.5) * var(--ih) * var(--zk))) scale(var(--zk))}
.cam img{width:100%;height:100%;object-fit:cover}
/* Every unit below the opening starts out marked .far, and scroll.js keeps the
   mark on the ones that are not on screen or next to it: the browser leaves
   their pictures alone (and does not fetch them) until they come near.
   auto, not hidden: the alt text stays in the accessibility tree, a canvas
   that does reach the screen is drawn at once, and it works without scripts. */
.far .canvas{content-visibility:auto}
/* The opening panorama always covers its frame and looks at --s across its width. */
.cam.cover{--iw:max(100cqw,calc(100cqh * 3));top:50%;height:calc(var(--iw) / 3);
  transform:translate(clamp(calc(100cqw - var(--iw)),calc(50cqw - var(--s,.5) * var(--iw)),0px),-50%)}

/* ---------- opening ---------- */
.hero .stage{container-type:inline-size;display:flex;flex-direction:column;min-height:100svh;
  padding-top:calc(clamp(14px,3svh,36px) + env(safe-area-inset-top));padding-bottom:max(clamp(14px,3.5svh,44px),env(safe-area-inset-bottom))}
.hero-in{flex:1 1 auto;display:flex;flex-direction:column;min-height:0}
.wordmark{font:clamp(24px,2.1vw,32px)/1 var(--display);letter-spacing:-.02em}
.hero .wordmark{flex:none;padding-block:6px 4px}
.intro{flex:none;display:grid;grid-template-columns:minmax(0,1fr) minmax(300px,34%);align-items:end;gap:4%;padding-block:clamp(8px,2svh,26px) clamp(14px,2.8svh,34px)}
h1{font-size:min(clamp(48px,7.4vw,128px),16svh);line-height:.98;letter-spacing:-.045em}
.lede{font-size:clamp(16px,1.25vw,21px);line-height:1.42;color:var(--ink-dim);max-width:40ch}
/* The two links: always on the first screen, plain, each a name and a label. */
.go{display:flex;flex-wrap:wrap;gap:0 clamp(22px,3vw,48px);margin-top:clamp(10px,1.8svh,20px)}
.go a{display:flex;flex-direction:column;justify-content:center;min-height:52px;padding-block:3px}
.go-name{font:clamp(23px,1.9vw,29px)/1.15 var(--display);letter-spacing:-.01em;white-space:nowrap;
  text-decoration:underline;text-decoration-color:var(--bronze);text-decoration-thickness:1px;text-underline-offset:.2em}
.go-label{font-size:16px;line-height:1.3;color:var(--ink-dim)}
.go a:hover .go-name{color:var(--bronze)}
.panorama{flex:1 1 0;min-height:120px;position:relative}
/* The panorama is three wide by one high, and a little smaller than a door. */
.pan-box{position:absolute;left:0;right:0;top:0;bottom:0;margin-block:auto;height:min(100%,calc(var(--dw) * 1.9 / 3))}
.pan-box .canvas{--s:calc((var(--s0) + var(--s1)) / 2);width:min(100%,calc(var(--dw) * 1.9));height:100%;margin-inline:auto}
/* The horizon: from beyond the left edge to the right-hand side, then down. */
.pan-box .line{z-index:2;transform:translate3d(0,calc((1 - var(--u)) * 100%),0)}
.pan-box .line i{transform:none}
.pan-box .line .run{left:-100vw;right:calc(var(--gr) - max(var(--side),calc((100cqw - var(--wrap)) / 2)))}
.pan-box .line .out{top:0;bottom:auto;height:300vh;left:calc(100% + max(var(--side),calc((100cqw - var(--wrap)) / 2)) - var(--gr) - var(--lw))}

/* ---------- chapter lines ---------- */
.chapter{position:relative;display:grid;place-items:center;min-height:30svh;padding:5svh var(--side);text-align:center}
.chapter h2{font-size:clamp(42px,7.6vw,116px);line-height:1;letter-spacing:-.04em;text-wrap:balance}
/* the line passing down the side between two stages */
.chapter::after{content:"";position:absolute;top:0;bottom:0;width:var(--lw);background:var(--bronze)}
.side-l::after{left:var(--gl)}
.side-r::after{right:var(--gr)}

/* ---------- landmark scenes ----------
   --a is the frame's aspect, --vv the share of the picture's height in view.
   The frame is 80% of the screen's height where its shape and the screen's
   width allow, always clear of the header, and never so large that the picture
   is enlarged past 1.3 times its pixels (--px). */
.scene{--a:var(--fa);--vv:var(--v);--cyy:var(--cy);--cxx:calc(var(--cx0) + (var(--cx1) - var(--cx0)) * var(--m));--dd:var(--d,0);
  --pad:clamp(30px,7svh,80px);
  --cw:min(88vw,calc(80svh * var(--a)),calc((100svh - var(--hdr) - 4rem) * var(--a)),var(--px));--ch:calc(var(--cw) / var(--a));
  --ct:var(--pad);                                           /* top of the canvas within the stage */
  --ly:calc(var(--ct) + var(--ch) * (1 - var(--u)))}          /* the line rides the paint edge */
.scene:not(.over){--ly:calc(var(--ct) + var(--ch) * var(--dd))} /* or rests at the waterline, the deck, the podium */
.scene .stage{display:grid;place-items:center;padding-block:var(--pad)}
.sheet{position:relative;z-index:1}
.scene.climb{--cyy:var(--cyz);--zk:calc(var(--v) / var(--vz))} /* at rest: stepped back, the whole tower */

/* ---------- inventions ----------
   --U is the width of one unit of track; an ordinary plate takes one unit, a
   featured plate --k units. */
.inventions{--k:1.45;--fw:min(88vw,calc((100svh - var(--hdr) - 9rem) * 1.5),calc(var(--dw) * 1.31),1536px);--fh:calc(var(--fw) / 1.5);
  --U:calc(var(--fw) / (var(--k) - .12));--ow:calc(var(--U) * .88);--A:.95;--B:1;
  --pad:clamp(30px,7svh,80px);--ly:calc(var(--pad) * .5)}
.inventions .stage{container-type:inline-size;padding-block:var(--pad)}
.track{width:min(calc(100% - 2 * var(--side)),1200px);margin-inline:auto}
.group + .group{margin-top:clamp(36px,7svh,72px)}
.chap{font:italic clamp(24px,2.3vw,34px)/1.12 var(--display);margin-bottom:18px}
.plates{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,300px),1fr));gap:clamp(26px,4vw,44px)}
.plate.feat{grid-column:1/-1;max-width:var(--fw)}
.plate .canvas{width:100%;height:auto;aspect-ratio:3/2;outline:0;box-shadow:0 18px 44px rgba(0,0,0,.4)}
.cap{margin-top:14px;font-size:16px;line-height:1.45;color:var(--ink-dim);max-width:44ch}

/* ---------- doors ---------- */
.doors{position:relative;container-type:inline-size;padding-bottom:clamp(44px,9svh,110px)}
.door-head{position:relative;padding:clamp(34px,8svh,88px) var(--side) clamp(22px,4.5svh,52px)}
.door-head h2{font-size:clamp(42px,7.6vw,116px);line-height:1;letter-spacing:-.04em}
.door-head::after{content:"";position:absolute;top:0;bottom:0;right:var(--gr);width:var(--lw);background:var(--bronze)}        /* down the right-hand side */
.door-grid{position:relative;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--dgap);padding-top:clamp(26px,5.5svh,60px);padding-bottom:12px;overflow-x:visible;overflow-y:clip}
.door-grid::before{content:"";position:absolute;top:0;height:var(--lw);background:var(--bronze);                                 /* across */
  left:calc((100% - var(--dgap)) / 4);right:calc(var(--gr) - max(var(--side),calc((100cqw - var(--wrap)) / 2)))}
.door{position:relative;z-index:1;display:block;background:var(--page)}
.door:first-child{z-index:2}
.door::before{content:"";position:absolute;left:50%;bottom:100%;width:var(--lw);height:300vh;margin-left:calc(var(--lw) / -2);background:var(--bronze)} /* and one branch into each door */
.door .canvas{container-type:normal;width:100%;height:auto;aspect-ratio:4/5;outline:0;border-top:var(--lw) solid var(--bronze);transition:box-shadow .2s}
.door .canvas img{width:100%;height:100%;object-fit:cover}
.door-text{padding:22px 2px 6px}
.kicker{font:16px/1.4 var(--label);letter-spacing:.08em;text-transform:uppercase;color:var(--ink-dim)}
.door h3{font-size:clamp(36px,3.6vw,60px);line-height:1.06;letter-spacing:-.03em;margin:6px 0 8px}
.door-text p:not(.kicker){color:var(--ink-dim);max-width:36ch}
.door:hover h3,.door:focus-visible h3{color:var(--bronze)}
.door:focus-visible{outline-offset:6px}

/* ---------- close: bookend, colophon, footer ---------- */
.close{padding-top:clamp(40px,8svh,96px);border-top:1px solid var(--rule)}
.bookend .canvas{width:min(100%,560px);height:auto;aspect-ratio:3/1;container-type:normal;outline-offset:7px}
.bookend .canvas img{width:100%;height:100%;object-fit:cover}
.colophon{display:grid;grid-template-columns:1fr 2fr;align-items:baseline;gap:24px;padding-block:clamp(30px,6svh,64px) clamp(40px,8svh,88px)}
.colophon h2{font:italic 34px/1.1 var(--display)}
.colophon p{max-width:50ch;font:clamp(20px,1.6vw,24px)/1.5 var(--display)}
.foot{display:flex;align-items:center;justify-content:space-between;padding-block:14px calc(18px + env(safe-area-inset-bottom));border-top:1px solid var(--rule)}
.foot a{display:inline-flex;align-items:center;min-height:44px}
.foot .return{font:16px/1 Arial,Helvetica,sans-serif;color:var(--ink-dim)}
.foot a:hover{color:var(--bronze)}

/* =====================================================================
   Motion. scroll.js adds .motion (plus .sda or .raf) to <html> unless the
   visitor prefers reduced motion. Without it, everything above is the page:
   finished paintings, static, unpinned.
   Every value below is a function of the three scroll numbers and nothing else.
   ===================================================================== */
/* Nothing on this page loads late and pushes content down, so scroll anchoring
   has no work to do. Left on, WebKit takes a moving chapter line for a layout
   shift and lands anchor jumps short. */
html.motion body{overflow-anchor:none}
html.motion .pin{height:calc((100 + var(--len) * var(--hold)) * 1svh)}
html.motion .pin > .stage{position:sticky;top:0;height:100svh;min-height:0}

/* Driver 1: CSS scroll-driven animation.
   --p: the timeline's visible range is inset to the top edge of the scrollport,
   so "cover" runs from the section top reaching the top of the screen to the
   section bottom reaching it; the range stops 100svh short, where the pin lets go. */
@keyframes kp{from{--p:0}to{--p:1}}
@keyframes kt{from{--t:0}to{--t:1}}
@keyframes kg{from{--g:0}to{--g:1}}
html.sda .pin{animation:kp linear both;animation-timeline:view(block 0% 100%);animation-range:cover 0% cover calc(100% - 100svh)}
html.sda .chapter{animation:kt linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
html.sda :is(.bar,.bar-chap span,.rail-fill),html.sda body::before{animation:kg linear both;animation-timeline:scroll(root block)}
/* Driver 2: scroll.js writes the numbers inline from requestAnimationFrame. */
html.raf .pin{--p:0}

/* Chapter lines travel a little faster than the page. */
html.motion .chapter .type{transform:translate3d(0,calc((.5 - var(--t)) * 10svh),0)}

/* Opening: the horizon lifts off the ground and the panorama is painted
   beneath it. On a narrow screen the camera pans left to right as it goes. */
html.motion .hero{--u:clamp(0,calc(var(--p) / .85),1)}
html.motion .pan-box .canvas{--s:calc(var(--s0) + (var(--s1) - var(--s0)) * var(--u))}
html.motion .hero .paint{clip-path:inset(calc((1 - var(--u)) * 100%) 0 0 0)}

/* Landmarks. In every scene the canvas is centred under the header. */
html.motion .scene{--ct:calc((100svh + var(--hdr) - var(--ch)) / 2)}
html.motion .scene .stage{padding:var(--hdr) 0 0}

/* build (the pyramid): PLAN 0-.05, RAISE .05-.36, PAINT .36-.86, HOLD.
   The sheet lies back 35 degrees with its chalk plan showing. The chalk
   elevation rises while the line waits on the plan; then the line climbs,
   the painting follows right behind it, and the sheet stands up.
   The line is drawn on the stage, not on the tilted sheet, so --ly works out
   where a point --u of the way up the sheet lands on screen: the sheet turns
   about its bottom edge under a perspective of twice its height.
   --tilt0 is how far back the sheet lies at the start: 35 degrees where the
   sheet is at least .72 of the screen's height, and less where it is smaller
   (a phone held upright), because a steep tilt would flatten a small drawing
   to a sliver. The drawing reaches 64% of the way up the sheet; lying back t
   degrees it stands about (.64 - .00563 t) of the sheet's height on screen,
   and --tilt0 is the t that keeps that at 31.5% of the screen's height.
   tan(atan2(a,b)) is a / b for two lengths.
   --c0 is how much of the chalk shows from the first frame: the plan strip, or
   more where the strip alone would be small on screen. It is the share of the
   sheet that, lying back --tilt0, stands 32% of the screen's height (the same
   projection as --ly, solved for the share). */
html.motion .build{
  --tilt0:clamp(0,calc(113.7 - 55.95 * tan(atan2(100svh,var(--ch)))),35);--r0:calc(var(--tilt0) * 1deg);
  --raise:clamp(0,calc((var(--p) - .05) / .31),1);
  --pt:clamp(0,calc((var(--p) - .36) / .5),1);
  --stand:clamp(0,calc(var(--pt) / .6),1);
  --tilt:calc(var(--tilt0) * (1 - .2 * var(--raise) - .8 * var(--stand) * var(--stand) * (3 - 2 * var(--stand))));
  --c0:clamp(var(--strip),calc(2 * tan(atan2(32svh,max(1px,calc(2 * cos(var(--r0)) * var(--ch) - sin(var(--r0)) * 32svh))))),1);
  --c:calc(var(--c0) + (1 - var(--c0)) * var(--raise));
  --u:calc(var(--strip) * var(--raise) + (1 - var(--strip)) * var(--pt));
  --rad:calc(var(--tilt) * 1deg);
  --ly:calc(var(--ct) + var(--ch) - var(--ch) * var(--u) * cos(var(--rad)) * 2 / (2 + var(--u) * sin(var(--rad))));
}
html.motion .build .sheet{transform:perspective(calc(var(--ch) * 2)) rotateX(var(--rad));transform-origin:50% 100%}
html.motion .build .lines{clip-path:inset(calc((1 - var(--c)) * 100%) 0 0 0)}
html.motion :is(.build,.climb) .paint{clip-path:inset(calc((1 - var(--u)) * 100%) 0 0 0)}

/* sweep (the Colosseum, the bridge): the painting arrives along the wall or
   the span, left to right, while the camera travels the same way. */
html.motion .sweep{--m:clamp(0,calc(var(--p) / .9),1);--q:clamp(0,calc((var(--p) - .08) / .74),1)}
html.motion .sweep .paint{clip-path:inset(0 calc((1 - var(--q)) * 100%) 0 0)}

/* spread (the Taj Mahal): from the waterline up into the building and down
   into its reflection, together. */
html.motion .spread{--q:clamp(0,calc((var(--p) - .08) / .72),1)}
html.motion .spread .paint{clip-path:inset(calc(var(--dd) * (1 - var(--q)) * 100%) 0 calc((1 - var(--dd)) * (1 - var(--q)) * 100%) 0)}

/* climb (the two towers): the camera rises with the line from the plan to the
   top, then steps back to take in the whole tower. */
html.motion .climb{
  --u:clamp(0,calc((var(--p) - .05) / .64),1);
  --bk:clamp(0,calc((var(--p) - .73) / .2),1);
  --back:calc(var(--bk) * var(--bk) * (3 - 2 * var(--bk)));
  --cyy:calc(var(--cy) + (var(--cyb) - var(--cy)) * var(--u) + (var(--cyz) - var(--cyb)) * var(--back));
  --zk:calc(var(--v) / (var(--v) + (var(--vz) - var(--v)) * var(--back)));
}

/* open (the Opera House): outward from the podium, like its shells. */
html.motion .open{--q:clamp(0,calc((var(--p) - .08) / .72),1)}
html.motion .open .paint{clip-path:ellipse(calc(var(--q) * 135%) calc(var(--q) * 112%) at 50% calc(var(--dd) * 100%))}

/* Inventions: one pinned track. --X is the point of the track at the middle of
   the screen, in units. It stands still on each featured plate and travels
   between them: three stretches of travel for four featured plates.
   An ordinary plate's painting fades in as the plate comes across (from --A
   units right of centre, over --B units); a featured plate's fades in while
   the track is standing still. Nothing inside a frame moves during a fade.
   The strip is centred in the room under the header: every plate, ordinary or
   featured, sits on the same centre line. --bh is the height of the tallest
   plate; the bronze line runs along the top of that box and the chapter name
   sits on it. A featured plate is as tall as the room allows, an ordinary one
   .88 / (k - .12) of that: at least 55% of the screen's height on a landscape
   screen that is 1.15 wide for 1 high or wider (narrower than that, the
   screen's width is the limit). No picture is enlarged past 1.3 times its
   pixels. */
html.motion .inventions{
  --k:1.2;--fw:min(88vw,calc((100svh - var(--hdr) - clamp(7rem,16svh,9rem)) * 1.5),1997px);--fh:calc(var(--fw) / 1.5);--bh:var(--fh);
  --X:calc(.5 * var(--k) + (var(--n1) + var(--k)) * clamp(0,calc((var(--p) - var(--s1)) / var(--d1)),1)
    + (var(--n2) + var(--k)) * clamp(0,calc((var(--p) - var(--s2)) / var(--d2)),1)
    + (var(--n3) + var(--k)) * clamp(0,calc((var(--p) - var(--s3)) / var(--d3)),1));
  --ly:calc((100svh + var(--hdr) - var(--bh)) / 2);
}
html.motion .inventions .stage{padding:0}
html.motion .track{position:absolute;left:50%;top:var(--ly);display:flex;width:max-content;height:var(--bh);margin:0;transform:translate3d(calc(var(--X) * var(--U) * -1),0,0)}
html.motion .group{position:relative;display:flex;flex:none;height:100%;margin:0}
html.motion .plates{position:relative;z-index:1;display:flex;align-items:center;gap:0;height:100%}
html.motion .plate{flex:none;width:var(--U);padding-inline:calc(var(--U) * .06);
  --rev:clamp(0,calc((var(--X) - var(--ca) - var(--cb) * var(--k) + var(--A)) / var(--B)),1)}
html.motion .plate.feat{width:calc(var(--U) * var(--k));max-width:none;--rev:clamp(0,calc((var(--p) - var(--f0)) / var(--f1)),1)}
html.motion .plate .canvas{width:100%;height:calc(var(--ow) / 1.5);aspect-ratio:auto}
html.motion .plate.feat .canvas{height:var(--fh)}
html.motion .plate .paint{opacity:var(--rev)}
/* The one caption hangs under its frame without moving the frame off the centre line. */
html.motion .plate figure{position:relative}
html.motion .cap{position:absolute;left:0;right:0;top:100%}
/* The chapter name sits on the line, above the strip, and stays at the left of
   the screen for as long as its chapter is passing (--chw is the room it is
   given before the next chapter pushes it out). */
html.motion .chap{position:absolute;left:calc(var(--U) * .06);bottom:100%;margin:0 0 clamp(8px,1.6svh,16px);white-space:nowrap;
  transform:translate3d(clamp(0px,calc((var(--X) - var(--ga) - var(--gb) * var(--k) - .06) * var(--U) + var(--side) - 50cqw),calc((var(--gwa) + var(--gwb) * var(--k) - .12) * var(--U) - var(--chw,24rem))),0,0)}

/* ---------- portrait: the phone is its own layout ---------- */
@media (max-width:900px){
  .intro{grid-template-columns:1fr;gap:12px}
  .lede{max-width:46ch}
}
@media (max-width:719px){
  :root{--hdr:56px}
  body{font-size:16px}
  /* Slim bar: wordmark and links on one line, the chapter name tucked under them. */
  .bar-in{grid-template-columns:minmax(0,1fr) auto;grid-template-rows:34px 22px;align-items:start;gap:0 10px;padding-inline:max(12px,env(safe-area-inset-left)) max(8px,env(safe-area-inset-right))}
  .bar-mark{grid-area:1/1;font-size:19px;height:44px;align-self:start}
  .bar-links{grid-area:1/2;gap:2px;margin-bottom:-10px}
  .bar-links a{font-size:17px;padding-inline:5px}
  .bar-chap{grid-area:2/1/3/3;height:22px;font:italic 16px/20px var(--display);text-align:left;pointer-events:none}
  .colophon{grid-template-columns:1fr;gap:12px}
}
@media (max-width:359px){.bar-links .ne{display:none}}
/* Two compact rows for the opening links. */
@media (max-width:560px){
  .go{display:block;margin-top:10px;border-bottom:1px solid var(--rule)}
  .go a{flex-direction:row;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:0 12px;min-height:46px;padding-block:9px 7px;border-top:1px solid var(--rule)}
  .go-name{font-size:22px}
}
@media (max-aspect-ratio:1/1){
  :root{--hold:.85}
  .pan-box{height:min(100%,104vw)}
  .pan-box .canvas{width:100%}
  .scene{--a:var(--fap);--vv:var(--vp,var(--v));--cyy:var(--cyp,var(--cy));--dd:var(--dp,var(--d,0));
    --cw:min(92vw,760px,calc((100svh - var(--hdr) - 5rem) * var(--a)),var(--pxp))}
  .climb{--cw:min(84vw,700px,calc((100svh - var(--hdr) - 5rem) * var(--a)),var(--pxp))}
  .inventions{--k:1.19;--fw:min(92vw,760px,calc((100svh - var(--hdr) - 8rem) * .86));--fh:calc(var(--fw) / .86);--A:.6;--B:.5;--chw:86vw}
  /* Every plate is as wide as the screen allows. A plate whose subject is
     compact (.crop) fills a tall frame centred on the subject (--th, at least
     58% of the screen's height where the frame can stay wider than .76 : 1;
     the frame is always between .76 and .86 wide for 1 high, which is what the
     generator checks each subject centre against).
     A plate whose subject is wide keeps its whole width: three wide by two
     high is all the height an uncut picture has on a portrait screen. */
  html.motion .inventions{--k:1;--fw:min(92vw,760px,calc((100svh - var(--hdr) - 8rem) * .86));
    --th:min(calc(100svh - var(--hdr) - 8rem),max(calc(var(--fw) / .86),min(58svh,calc(var(--fw) / .76))));--bh:var(--th)}
  .chap{font-size:clamp(22px,5.6vw,30px)}
  html.motion .plate.crop{--cxx:var(--s)}
  html.motion .plate.crop .canvas{height:var(--th)}
  .door-grid{grid-template-columns:minmax(0,1fr);gap:clamp(34px,6svh,60px)}
  .door-grid::before{left:30%}
  .door:first-child::before{left:30%}
  .door:last-child::before{left:70%}
}
/* Short landscape screens (a phone on its side). */
@media (max-height:520px) and (orientation:landscape){
  :root{--hdr:48px;--hold:.8}
  .hero .stage{padding-top:calc(12px + env(safe-area-inset-top));padding-bottom:max(8px,env(safe-area-inset-bottom))}
  .hero .wordmark{display:none}
  .intro{grid-template-columns:minmax(0,1fr) minmax(0,50%);gap:3%;padding-block:4px 8px}
  h1{font-size:min(clamp(40px,6vw,128px),15svh)}
  .lede{font-size:16px;line-height:1.3}
  .go{margin-top:4px}
  .go a{min-height:46px}
  .go-name{font-size:21px}
  .panorama{min-height:80px}
  .scene{--a:var(--fas);--cw:min(88vw,calc((100svh - var(--hdr) - 2rem) * var(--a)),var(--px))}
  .inventions{--k:1.5;--fw:min(80vw,calc((100svh - var(--hdr) - 3rem) * 1.5),calc(var(--dw) * 1.31))}
  html.motion .inventions{--k:1.15;--fw:min(80vw,calc((100svh - var(--hdr) - 3.4rem) * 1.5))}
  html.motion .chap{font-size:18px;line-height:1;margin-bottom:5px}
  /* No room under the frame for the one caption: it sits on the foot of the picture. */
  html.motion .cap{top:auto;bottom:0;margin:0;max-width:none;padding:6px 10px;background:rgba(28,27,26,.9);color:var(--ink)}
  .chapter{min-height:40svh}
  .bar-links a,.bar-mark{min-height:44px}
}
/* Short and narrow: the two-row phone bar keeps its height. */
@media (max-height:520px) and (orientation:landscape) and (max-width:719px){:root{--hdr:56px}}
/* A desktop window zoomed far in is a very small landscape screen. Too narrow
   for two columns; and when it is too short to hold the opening, the opening
   is not pinned and its painting is shown finished. */
@media (max-height:520px) and (orientation:landscape) and (max-width:560px){
  .intro{grid-template-columns:1fr;gap:8px}
}
@media (max-height:320px){
  html.motion .hero{height:auto;--u:1}
  html.motion .hero > .stage{position:static;height:auto}
  .panorama{flex:none;height:max(120px,30vw)}
}
/* Forced colours replace backgrounds, which is all the line is drawn with. */
@media (forced-colors:active){
  .line i,.rail-fill,.chapter::after,.door-head::after,.door-grid::before,.door::before{background:CanvasText}
  .rail{background:GrayText}
}
@media (prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important}}
